Rails3教程系列之七:Rails3入门(6)

本文介绍了如何使用Rails进行代码重构,提高代码复用性,并通过局部模板减少重复代码。此外,还详细讲解了如何实现评论的创建、删除功能以及如何确保应用的安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 重构

现在, 我们博客的文章和评论都可以工作了, 但是如果我们看下 app/views/posts/show.html.erb 模板, 你会发现其代码又长又笨, 还记得Rails的信条么? DRY!(不要做重复的事, Dont Repeat Yourself)

现在我们使用局部模板来清理下这些代码吧.

首先我们制作一个comment模板来显示一条文章下的所有评论. 创建 app/views/comments/_comment.erb :

Html代码 复制代码 收藏代码
  1. <p> 
  2.   <b>Commenter:</b> 
  3.   <%= comment.commenter %> 
  4. </p> 
  5.   
  6. <p> 
  7.   <b>Comment:</b> 
  8.   <%= comment.body %> 
  9. </p> 
<p>
  <b>Commenter:</b>
  <%= comment.commenter %>
</p>
 
<p>
  <b>Comment:</b>
  <%= comment.body %>
</p>

然后修改 posts下面的show.html.erb模板:

Html代码 复制代码 收藏代码
  1. <p class="notice"><%= notice %></p> 
  2.   
  3. <p> 
  4.   <b>Name:</b> 
  5.   <%= @post.name %> 
  6. </p> 
  7.   
  8. <p> 
  9.   <b>Title:</b> 
  10.   <%= @post.title %> 
  11. </p> 
  12.   
  13. <p> 
  14.   <b>Content:</b> 
  15.   <%= @post.content %> 
  16. </p> 
  17.   
  18. <h2>Comments</h2> 
  19. <%= render @post.comments %> 
  20.   
  21. <h2>Add a comment:</h2> 
  22. <%= form_for([@post, @post.comments.build]) do |f| %> 
  23.   <div class="field"> 
  24.     <%= f.label :commenter %><br /> 
  25.     <%= f.text_field :commenter %> 
  26.   </div> 
  27.   <div class="field"> 
  28.     <%= f.label :body %><br /> 
  29.     <%= f.text_area :body %> 
  30.   </div> 
  31.   <div class="actions"> 
  32.     <%= f.submit %> 
  33.   </div> 
  34. <% end %> 
  35.   
  36. <br /> 
  37.   
  38. <%= link_to 'Edit Post', edit_post_path(@post) %>
  39. <%= link_to 'Back to Posts', posts_path %>
<p class="notice"><%= notice %></p>
 
<p>
  <b>Name:</b>
  <%= @post.name %>
</p>
 
<p>
  <b>Title:</b>
  <%= @post.title %>
</p>
 
<p>
  <b>Content:</b>
  <%= @post.content %>
</p>
 
<h2>Comments</h2>
<%= render @post.comments %>
 
<h2>Add a comment:</h2>
<%= form_for([@post, @post.comments.build]) do |f| %>
  <div class="field">
    <%= f.label :commenter %><br />
    <%= f.text_field :commenter %>
  </div>
  <div class="field">
    <%= f.label :body %><br />
    <%= f.text_area :body %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
 
<br />
 
<%= link_to 'Edit Post', edit_post_path(@post) %> |
<%= link_to 'Back to Posts', posts_path %> |

这将为每条评论渲染 app/views/comments/下面的_comment.erb局部模板, 因为传入 render 方法的参数是一个集合 (<%= render @post.comments %>), rails会自动判断参数是否是集合, 如果是, 将遍历集合同时输出局部模板 (在这里, _comment.erb局部模板的变量名称为 comment, 然后comments集合的每个元素分配给该comment变量)

请想想 form_for [@post, @post.comments.build] 方法生成表单的action为: posts/:id/comment, 那么对于REST路由, 我们在后面将会深入了解.

同样, 我们把创建评论部分也移到局部模板中去, 创建文件 app/views/comments/_form.erb:

Html代码 复制代码 收藏代码
  1. <%= form_for([@post, @post.comments.build]) do |f| %> 
  2.   <div class="field"> 
  3.     <%= f.label :commenter %> 
  4.     <%= f.text_field :commenter %> 
  5.   </div> 
  6.   <div class="field"> 
  7.     <%= f.label :body %> 
  8.     <%= f.text_area :body %> 
  9.   </div> 
  10.   <div class="actions"> 
  11.     <%= f.submit %> 
  12.   </div> 
  13. <% end %> 
<%= form_for([@post, @post.comments.build]) do |f| %>
  <div class="field">
    <%= f.label :commenter %>
    <%= f.text_field :commenter %>
  </div>
  <div class="field">
    <%= f.label :body %>
    <%= f.text_area :body %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

最后的show.html.erb为这个样子:

Html代码 复制代码 收藏代码
  1. <p class="notice"><%= notice %></p> 
  2.   
  3. <p> 
  4.   <b>Name:</b> 
  5.   <%= @post.name %> 
  6. </p> 
  7.   
  8. <p> 
  9.   <b>Title:</b> 
  10.   <%= @post.title %> 
  11. </p> 
  12.   
  13. <p> 
  14.   <b>Content:</b> 
  15.   <%= @post.content %> 
  16. </p> 
  17.   
  18. <h2>Comments</h2> 
  19. <%= render @post.comments %> 
  20.   
  21. <h2>Add a comment:</h2> 
  22. <%= render "comments/form" %> 
  23.   
  24. <br /> 
  25.   
  26. <%= link_to 'Edit Post', edit_post_path(@post) %>
  27. <%= link_to 'Back to Posts', posts_path %>
<p class="notice"><%= notice %></p>
 
<p>
  <b>Name:</b>
  <%= @post.name %>
</p>
 
<p>
  <b>Title:</b>
  <%= @post.title %>
</p>
 
<p>
  <b>Content:</b>
  <%= @post.content %>
</p>
 
<h2>Comments</h2>
<%= render @post.comments %>
 
<h2>Add a comment:</h2>
<%= render "comments/form" %>
 
<br />
 
<%= link_to 'Edit Post', edit_post_path(@post) %> |
<%= link_to 'Back to Posts', posts_path %> |

  第二个局部模板就比较简单了, 没有变量的赋值, 仅仅引用了comments下的_form.erb模板, 通过"/", rails知道你渲染的是comments文件夹下的_form模板.

再次说明一点的是: @post 作用于任何该视图下的局部模板, 因为它是一个实例变量.

2. 删除评论

博客中另一个重要特性是可以删除垃圾评论, 要实现该功能, 我们需要在每条评论下建立一个链接, 并实现CommentController下面的destroy动作.

所以首先, 我们先在_comment.erb模板下添加一条删除链接:

Html代码 复制代码 收藏代码
  1. <p> 
  2.   <b>Commenter:</b> 
  3.   <%= comment.commenter %> 
  4. </p> 
  5.   
  6. <p> 
  7.   <b>Comment:</b> 
  8.   <%= comment.body %> 
  9. </p> 
  10.   
  11. <p> 
  12.   <%= link_to 'Destroy Comment', [comment.post, comment], 
  13.                :confirm => 'Are you sure?', 
  14.                :method => :delete %> 
  15. </p> 
<p>
  <b>Commenter:</b>
  <%= comment.commenter %>
</p>
 
<p>
  <b>Comment:</b>
  <%= comment.body %>
</p>
 
<p>
  <%= link_to 'Destroy Comment', [comment.post, comment],
               :confirm => 'Are you sure?',
               :method => :delete %>
</p>

同样也请留意下 link_to 生成的url: posts/:id/comments/:id, 以及产生一个delete请求(注意不是get, 想想如果可以通过get来删除数据是不是很糟糕? 一般来说对于查询数据我们使用get请求, 对于操作数据使用post请求, 所以对于一个搜索功能来说, 即使是表单提交, 那么我们也应该把表单的method设为get)

接下来我们实现CommentsController下的destroy方法(怎么会调用该方法? 记住这是一个REST)

Ruby代码 复制代码 收藏代码
  1. def destroy 
  2.   @post = Post.find(params[:post_id]) 
  3.   @comment = @post.comments.find(params[:id]) 
  4.   @comment.destroy 
  5.   redirect_to(post_path(@post)) 
  6. end 
  def destroy
    @post = Post.find(params[:post_id])
    @comment = @post.comments.find(params[:id])
    @comment.destroy
    redirect_to(post_path(@post))
  end

destroy方法首先找到该篇文章, 然后在@post.comments集合内锁定需要删除的评论, 删除之后跳转到该文章地址.

3. 删除关联对象

如果你删除一篇文章, 那么相关的评论也一并删除. 否则评论还将继续留在数据库中占用空间. Rails同样允许你使用依赖选项来激活. 修改Post模型:

Ruby代码 复制代码 收藏代码
  1. class Post < ActiveRecord::Base 
  2.   validates :name:presence => true 
  3.   validates :title, :presence => true
  4.                     :length => { :minimum => 5 } 
  5.   has_many :comments, :dependent => :destroy 
  6. end 
class Post < ActiveRecord::Base
  validates :name,  :presence => true
  validates :title, :presence => true,
                    :length => { :minimum => 5 }
  has_many :comments, :dependent => :destroy
end

:dependent => :destroy 告诉rails当删除一条post时, 相关的comments将调用destroy方法一并删除, 如果设置为 :delete_all 那么关联对象将被删除而不调用它们的 destroy 方法, 如果设置为 :nullify, 所有关联对象的外键将被设为 null 而不调用他们的 save 回调; 如果设置为 :restrict 那么该对象在有关联对象存在的时候无法被删除. (注意一点的是 :dependent 在使用 :through 选项时将被忽略)

4. 安全

现在我们要发布博客里, 可以我们发现所有人都可以添加 删除 修改文章和评论.

那么rails提供了一个非常简单的HTTP认证, 那么我们需要在全局控制器内实现它:

app/controllers/application_controller.rb

Ruby代码 复制代码 收藏代码
  1. class ApplicationController < ActionController::Base 
  2.   protect_from_forgery 
  3.   
  4.   private 
  5.   
  6.   def authenticate 
  7.     authenticate_or_request_with_http_basic do |user_name, password| 
  8.       user_name == 'admin' && password == 'password' 
  9.     end 
  10.   end 
  11.   
  12. end 
class ApplicationController < ActionController::Base
  protect_from_forgery
 
  private
 
  def authenticate
    authenticate_or_request_with_http_basic do |user_name, password|
      user_name == 'admin' && password == 'password'
    end
  end
 
end

然后我们需要在PostsController阻止未认证用户的一些动作的访问, 那么在这里我们可以使用 before_filter 过滤器. 该方法将在每个动作执行前运行, 除非一些通过 :except 设置的方法:

Ruby代码 复制代码 收藏代码
  1. class PostsController < ApplicationController 
  2.   
  3.   before_filter :authenticate, :except => [:index, :show
  4.   ... 
  5. end 
class PostsController < ApplicationController
 
  before_filter :authenticate, :except => [:index, :show]
  ...
end

同样的, 我们只允许认证用户可以删除评论:

Ruby代码 复制代码 收藏代码
  1. class CommentsController < ApplicationController 
  2.   
  3.   before_filter :authenticate, :only => :destroy 
  4.   ... 
  5. end 
class CommentsController < ApplicationController
 
  before_filter :authenticate, :only => :destroy
  ...
end

现在如果你创建post, 你将被要求输入用户名和密码.

Good Luck!

内容概要:文章阐述了构建安全教育体系以应对2025年挑战的目标、原则、内容设计、实施路径、预期成效及保障措施。面对日益复杂的社会安全形势,文章提出通过系统化、科学化、人性化的安全教育体系提升全民安全意识与应急能力。该体系涵盖知识普及、技能实训、文化培育三个模块,采用沉浸式学习工具、模块化训练、跨领域协作演练等方式。实施路径分为体系构建(2023-2024年)、试点推广(2024-2025年)、全面覆盖(2025年及以后)三个阶段。预期成效包括提升公众安全素养、降低事故发生率、增强社会韧性。保障措施涉及政策、资源、技术和评估四个方面,确保体系的有效运行。 适合人群:社会各界人士,特别是教育工作者、应急管理从业者、政策制定者以及关注公共安全的个人和组织。 使用场景及目标:①适用于各级学校、企业及社区的安全教育规划与实施;②为政策制定者提供构建安全教育体系的参考框架;③帮助教育工作者设计和优化安全教育课程与活动;④提升公众的安全意识与应急能力,降低安全事故的发生率。 其他说明:本文不仅提供了详细的构建方案,还强调了科学性、系统性、人本性和预见性的核心原则,旨在通过多维度、多层次的安全教育实践,推动安全文化深入人心,为社会的可持续发展奠定坚实基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值