在application_controller中设置变量并在模型中访问

时间:2018-07-01 03:09:25

标签: ruby-on-rails

在我的Application Controller中,我根据地理位置设置了一个货币变量:

class ApplicationController < ActionController::Base

  before_action :currency

  protected

  def currency
    cookies[:country] ||= request.location.country
    case cookies[:country]
    when "MY"
      c = "MYR"
    when "SG"
      c = "SGD"
    else
      c = "USD"
    end
    @currency = Currency.find_by(name: c)
  end
end

我有使用价格方法的模型产品和多种货币,多种价格,即:一种产品可以采用自定义定价的多种货币。

class Product < ApplicationRecord
  has_many :prices
  has_many :currencies, through: :prices

  def price
    # how to access @currency?
  end

end

class Price < ApplicationRecord
  belongs_to :product
  belongs_to :currency
end

class Currency < ApplicationRecord
  has_many :prices
  has_many :products, through: :prices
end

在Model Product.price中访问@currency的最佳方法是什么?或者如何告诉方法仅以@currency返回价格?这可能不是最好的处理方法,请提出建议。

3 个答案:

答案 0 :(得分:3)

您的情况有些落后,因此您正在尝试解决错误的问题。模型不应该试图从控制器层获取信息,控制器应该将信息发送到模型中:

class Product < ApplicationRecord
  #...
  def price_in(currency)
    # Access the associations however you need to and handle missing
    # information however fits your application in here...
  end
end

,然后在您的控制器或视图中:

price = product.price_in(@currency)

您应该能够从任何地方(控制器,Rake任务,作业,控制台等)调用模型上的方法,而不必担心所有特定于请求的状态。

答案 1 :(得分:1)

不应该。这样做违反了许多设计原则,只会使自己沮丧。

您的模型不应在乎控制器的上下文。它应该只关心与自身相关的数据。

您可以使用ActiveModel::Attributes API。

在您的模型中:

class Product < ApplicationRecord
  has_many :prices
  has_many :currencies, through: :prices

  attribute :currency 

  def price
    self.currency 
  end

end

在您的控制器中:

class ProductsController < ApplicationController
  def show
    @product = Product.find(params[:id])
    @product.currency = @currency 
  end 
end

使用ActiveModel::Attributes API可以做更多的事情,例如设置默认值,运行验证,甚至设置对象的类型(布尔/真/假,整数,字符串等)。它的行为就像您在模型上的常规属性一样,只是它们不受数据库支持。

有关此出色的API https://apidock.com/rails/ActiveRecord/Attributes/ClassMethods/attribute

的更多信息

答案 2 :(得分:0)

查看this answer,了解有关如何访问模型中的cookie的信息。但是您应该考虑将此方法移出控制器,并移入Currency类,这似乎更合逻辑。然后,您可以从Product类中将方法称为Currency.get_currency。