Rails辅助方法 #

一、辅助方法概述 #

1.1 什么是辅助方法 #

辅助方法(Helper)是Rails提供的视图辅助方法,用于简化视图代码,保持视图简洁。

1.2 辅助方法位置 #

text
app/helpers/
├── application_helper.rb    # 全局辅助方法
├── articles_helper.rb       # 文章相关辅助方法
└── users_helper.rb          # 用户相关辅助方法

二、内置辅助方法 #

2.1 链接辅助方法 #

erb
<!-- 基本链接 -->
<%= link_to '首页', root_path %>

<!-- 带HTML属性 -->
<%= link_to '文章', articles_path, class: 'btn', id: 'articles-link' %>

<!-- 带数据属性 -->
<%= link_to '删除', article_path(@article), 
    data: { 
      turbo_method: :delete, 
      turbo_confirm: '确定删除?' 
    } %>

<!-- 块链接 -->
<%= link_to article_path(@article) do %>
  <strong><%= @article.title %></strong>
<% end %>

<!-- 邮件链接 -->
<%= mail_to 'info@example.com', '联系我们' %>

<!-- 电话链接 -->
<%= phone_to '1234567890', '拨打电话' %>

<!-- SMS链接 -->
<%= sms_to '1234567890', '发送短信' %>

2.2 URL辅助方法 #

erb
<!-- 路径助手 -->
<%= root_path %>              <!-- / -->
<%= articles_path %>          <!-- /articles -->
<%= article_path(@article) %> <!-- /articles/1 -->
<%= new_article_path %>       <!-- /articles/new -->
<%= edit_article_path(@article) %> <!-- /articles/1/edit -->

<!-- URL助手 -->
<%= root_url %>               <!-- http://example.com/ -->
<%= articles_url %>           <!-- http://example.com/articles -->

<!-- 带参数 -->
<%= articles_path(page: 2) %> <!-- /articles?page=2 -->
<%= article_path(@article, format: :json) %> <!-- /articles/1.json -->

2.3 资源辅助方法 #

erb
<!-- 样式表 -->
<%= stylesheet_link_tag 'application' %>
<%= stylesheet_link_tag 'print', media: 'print' %>

<!-- JavaScript -->
<%= javascript_importmap_tags %>
<%= javascript_include_tag 'application' %>

<!-- 图片 -->
<%= image_tag 'logo.png', alt: 'Logo' %>
<%= image_tag 'icon.png', size: '16x16' %>
<%= image_tag 'photo.jpg', class: 'img-fluid' %>

<!-- 视频和音频 -->
<%= video_tag 'intro.mp4', controls: true %>
<%= audio_tag 'music.mp3', controls: true %>

<!-- favicon -->
<%= favicon_link_tag 'favicon.ico' %>

2.4 文本辅助方法 #

erb
<!-- 截断文本 -->
<%= truncate(@article.body, length: 100) %>
<%= truncate(@article.body, length: 100, omission: '...') %>

<!-- 高亮文本 -->
<%= highlight(@article.body, 'Rails') %>
<%= highlight(@article.body, ['Rails', 'Ruby']) %>

<!-- 简单格式化 -->
<%= simple_format(@article.body) %>
<%= simple_format(@article.body, class: 'paragraph') %>

<!-- 自动链接 -->
<%= auto_link(@article.body) %>
<%= auto_link(@article.body, html: { target: '_blank' }) %>

<!-- 复数化 -->
<%= pluralize(@articles.count, 'article') %>  <!-- 5 articles -->
<%= pluralize(1, 'person') %>  <!-- 1 person -->

<!-- 单词截断 -->
<%= word_wrap(@article.body, line_width: 80) %>

<!-- 首字母大写 -->
<%= titleize('hello world') %>  <!-- Hello World -->

2.5 数字辅助方法 #

erb
<!-- 格式化数字 -->
<%= number_with_delimiter(1234567) %>  <!-- 1,234,567 -->
<%= number_with_precision(3.14159, precision: 2) %>  <!-- 3.14 -->

<!-- 货币格式 -->
<%= number_to_currency(123.45) %>  <!-- $123.45 -->
<%= number_to_currency(123.45, unit: '¥') %>  <!-- ¥123.45 -->
<%= number_to_currency(123.45, format: '%n %u') %>  <!-- 123.45 ¥ -->

<!-- 百分比格式 -->
<%= number_to_percentage(0.5, precision: 0) %>  <!-- 50% -->
<%= number_to_percentage(0.523, precision: 2) %>  <!-- 52.30% -->

<!-- 电话格式 -->
<%= number_to_phone(1234567890) %>  <!-- 123-456-7890 -->

<!-- 文件大小 -->
<%= number_to_human_size(1234567) %>  <!-- 1.18 MB -->

<!-- 人类可读数字 -->
<%= number_to_human(1234567) %>  <!-- 1.23 Million -->

2.6 日期时间辅助方法 #

erb
<!-- 格式化日期 -->
<%= l Date.today, format: :long %>  <!-- 2024年3月28日 -->
<%= l Time.now, format: :short %>  <!-- 28日 15:30 -->

<!-- 距离时间 -->
<%= distance_of_time_in_words(Time.now, Time.now + 1.day) %>  <!-- about 1 day -->
<%= distance_of_time_in_words(Time.now, Time.now + 1.hour) %>  <!-- about 1 hour -->

<!-- 时间选择 -->
<%= time_ago_in_words(@article.created_at) %>  <!-- 2 hours ago -->

<!-- 时间标签 -->
<%= time_tag Date.today %>  <!-- <time datetime="2024-03-28">2024-03-28</time> -->
<%= time_tag Date.today, format: :long %>  <!-- <time datetime="2024-03-28">2024年3月28日</time> -->

2.7 数组辅助方法 #

erb
<!-- 循环 -->
<% ['one', 'two', 'three'].each_with_index do |item, index| %>
  <%= cycle('odd', 'even', name: 'row_class') %>  <!-- odd, even, odd -->
<% end %>

<!-- 安全连接 -->
<%= safe_join(['项目1', '项目2', '项目3'], ', ') %>  <!-- 项目1, 项目2, 项目3 -->

<!-- 截取数组 -->
<%= @articles.first(5) %>

2.8 标签辅助方法 #

erb
<!-- 内容标签 -->
<%= content_tag :div, class: 'container' do %>
  <p>内容</p>
<% end %>

<!-- 标签 -->
<%= tag.div class: 'container' do %>
  <p>内容</p>
<% end %>

<!-- 自闭合标签 -->
<%= tag.br %>
<%= tag.hr %>
<%= tag.img src: 'logo.png' %>

2.9 缓存辅助方法 #

erb
<!-- 缓存片段 -->
<% cache @article do %>
  <%= render @article %>
<% end %>

<!-- 缓存集合 -->
<%= render partial: 'article', collection: @articles, cached: true %>

<!-- 缓存过期 -->
<% cache [@article, current_user] do %>
  <%= render @article %>
<% end %>

2.10 调试辅助方法 #

erb
<!-- 调试输出 -->
<%= debug(@article) %>
<%= debug(params) %>

<!-- 美化输出 -->
<%= simple_format(@article.to_yaml) %>

<!-- 控制台 -->
<%= console %>

三、自定义辅助方法 #

3.1 创建辅助方法 #

ruby
# app/helpers/application_helper.rb
module ApplicationHelper
  def page_title(title)
    title.present? ? "#{title} | MyApp" : 'MyApp'
  end
  
  def format_date(date)
    date.strftime('%Y年%m月%d日') if date
  end
  
  def markdown(text)
    renderer = Redcarpet::Render::HTML.new
    markdown = Redcarpet::Markdown.new(renderer)
    markdown.render(text).html_safe
  end
  
  def author_link(article)
    link_to article.author.name, user_path(article.author)
  end
end

3.2 使用辅助方法 #

erb
<!-- app/views/layouts/application.html.erb -->
<title><%= page_title(yield(:title)) %></title>

<!-- app/views/articles/show.html.erb -->
<h1><%= @article.title %></h1>
<p><%= format_date(@article.created_at) %></p>
<div class="content">
  <%= markdown(@article.body) %>
</div>
<p>作者:<%= author_link(@article) %></p>

3.3 控制器辅助方法 #

ruby
# app/helpers/articles_helper.rb
module ArticlesHelper
  def article_status_badge(article)
    case article.status
    when 'published'
      content_tag :span, '已发布', class: 'badge bg-success'
    when 'draft'
      content_tag :span, '草稿', class: 'badge bg-secondary'
    when 'archived'
      content_tag :span, '已归档', class: 'badge bg-dark'
    end
  end
  
  def article_card(article)
    content_tag :div, class: 'card' do
      concat(content_tag(:div, class: 'card-header') do
        article.title
      end)
      concat(content_tag(:div, class: 'card-body') do
        truncate(article.body, length: 100)
      end)
    end
  end
end

3.4 表单辅助方法 #

ruby
# app/helpers/form_helper.rb
module FormHelper
  def error_messages_for(object)
    return '' if object.errors.empty?
    
    content_tag :div, class: 'alert alert-danger' do
      concat(content_tag(:h4, '请修正以下错误:'))
      concat(content_tag(:ul) do
        object.errors.full_messages.each do |message|
          concat(content_tag(:li, message))
        end
      end)
    end
  end
  
  def form_group(form, attribute, options = {})
    content_tag :div, class: 'form-group' do
      concat(form.label(attribute, class: 'form-label'))
      concat(form.text_field(attribute, class: 'form-control'))
      if options[:help]
        concat(content_tag(:small, options[:help], class: 'form-text'))
      end
    end
  end
end

四、辅助方法最佳实践 #

4.1 命名规范 #

ruby
# 推荐:动词开头
def format_date(date)
end

def render_article(article)
end

def display_status(status)
end

# 不推荐:名词开头
def date_format(date)
end

def article_renderer(article)
end

4.2 保持简洁 #

ruby
# 不推荐:复杂逻辑
def article_list(articles)
  html = ''
  articles.each do |article|
    html += '<div class="article">'
    html += "<h2>#{article.title}</h2>"
    html += "<p>#{article.body}</p>"
    html += '</div>'
  end
  html.html_safe
end

# 推荐:使用辅助方法
def article_list(articles)
  render partial: 'articles/article', collection: articles
end

4.3 避免业务逻辑 #

ruby
# 不推荐:辅助方法中包含业务逻辑
def article_price(article)
  if article.on_sale?
    article.price * 0.9
  else
    article.price
  end
end

# 推荐:业务逻辑放在模型中
# app/models/article.rb
class Article < ApplicationRecord
  def final_price
    on_sale? ? price * 0.9 : price
  end
end

# app/helpers/articles_helper.rb
def article_price(article)
  number_to_currency(article.final_price)
end

五、总结 #

5.1 核心要点 #

要点 说明
内置辅助方法 Rails提供的辅助方法
自定义辅助方法 在helpers目录创建
命名规范 动词开头
保持简洁 使用render等
避免业务逻辑 放在模型中

5.2 下一步 #

现在你已经掌握了辅助方法,接下来让我们学习 数据库配置,深入了解Rails的数据库系统!

最后更新:2026-03-28