20

我正在寻找编写某些方法来处理字符串,以及在我的许多控制器中发生的其他任务。我知道在控制器中包含助手是不好的做法,所以我只是想知道,在哪里放置控制器中使用的应用程序范围方法的最佳位置?

我意识到你们中的一些人会说将它们放入模型中,但您必须意识到并非我的所有控制器都有关联的模型。任何和所有输入将不胜感激。

4

6 回答 6

12

我倾向于把它们变成助手。它们自动包含在视图中的事实对我来说不是问题。您还可以将它们放入 app/concerns/ 或 lib/ 之类的位置

我不喜欢将 ApplicationController 与私有方法混为一谈,因为这通常会变得一团糟。

例子:

module AuthenticationHelper
  def current_user
    @current_user # ||= ...
  end

  def authenticate!
    redirect_to new_session_url unless current_user.signed_in?
  end
end

module MobileSubdomain
  def self.included(controller)
    controller.before_filter :set_mobile_format
  end

  def set_mobile_format
    request.format = :mobile if request.subdomain == "m"
  end
end

class ApplicationController
  include AuthenticationHelper
  include MobileSubdomain
end
于 2012-08-14T11:07:46.900 回答
10

如果您需要在应用程序范围内使用方法,那么我建议您将这些方法保留在应用程序控制器中,以便在视图中使用它们。将它们声明为辅助方法。

例如,

class ApplicationController < ActionController::Base
 helper_method :current_user, :some_method

 def current_user
   @user ||= User.find_by_id(session[:user_id])
 end

 def some_method
 end
end
于 2012-08-14T10:48:23.750 回答
9

我建议将它们放在lib文件夹中。所以例如我有:

lib/utils/string_utils

module StringUtils

  def foo
     ...
  end
end

class BarController < ActionController::Base
  include StringUtils
end

这展示了称为Fat model, Thin controller的好方法,在这种情况下,我们使用 Mixins 而不是 Models 来分离逻辑,但想法是相同的。您希望您的控制器尽可能简单。

于 2012-08-14T11:53:46.740 回答
3

这一切都取决于您的需求。我将在这里提供 2 个示例。它们都只是一个自定义库,位于lib目录下。

第一个例子——“自定义字符串处理”

# lib/filters.rb
module Filters

  # Converts value to canonical view
  def self.phone(value)
    # remove all non-digits
    clean_value = value.gsub(/\D/, '')

    country_codes = configus.phone.country_codes
    area_code = configus.phone.defaults.area_code

    case clean_value.length
      when 7
        "#{area_code}#{clean_value}"
      when 11
        # remove country code only if phone starts with the allowed country code
        if country_codes.include?(clean_value[0].to_i)
          clean_value[1..-1]
        else
          clean_value
        end
      else clean_value
    end
  end

# usage
# app/api/phones_controller.rb
class Api::PhonesController < Api::ApplicationController

  def exists
    if params[:q]
      clean_value = Filters.phone(params[:q])
      ...
    end
  end
end

第二个例子 - flash 消息的助手

# lib/flash_helper.rb
module FlashHelper
  def flash_translate(key, options = {})
    scope = [:flash, :controllers]
    scope += params[:controller].split('/')
    scope << params[:action]

    t(key, {:scope => scope}.merge(options))
  end
end

# app/application_controller.rb
class ApplicationController < ActionController::Base
  include FlashHelper
end

# usage
# app/your_controller.rb
class YourController < ApplicationController

  def create
    @object = Object.new(params[:object])

    if @object.save
      flash[:success] = flash_translate(:success)
      ...
    end
  end
end

注意:不要忘记将libdir 添加到自动加载路径。在config/application.rb添加/修改这一行config.autoload_paths += %W(#{config.root}/lib)。所以对我来说,答案是lib目录。

于 2012-08-14T18:12:15.533 回答
1

从 Rails 4 开始,它有一个专用文件夹app/controllers/concerns。因此,您可以在那里创建一个模块,然后将其包含在特定的控制器中,或者如果您需要它在所有控制器中都可用,则将其包含在 ApplicationController 中。

于 2017-08-10T08:04:56.803 回答
0

如果这些方法在许多控制器中使用,我会在application_controller.rb. 每个控制器都将从它继承,并且能够使用那里定义的任何方法

于 2012-08-14T10:48:58.010 回答