如何设置可以在Rails的控制器和模型中访问的“全局”变量

时间:2019-07-17 20:00:01

标签: ruby variables ruby-on-rails-4 global-variables activesupport-concern

我有一个已设置条目的表。我想在模型和控制器中将这些条目作为变量访问,而不必每次都查询数据库来设置这些变量。

我可以通过为模型和控制器创建重复的“问题”来使其工作。我也可以在ApplicationController中设置全局变量。或者,我可以在需要它们的每个地方初始化它们。设置和访问可以在控制器和模型中访问的全局变量的正确方法是什么?

class ItemType
  has_many :items
end

class Item
  belongs_to :item_type
  belongs_to :foo
end

class Foo 
  has_many :items  

  def build_item
    bar_item_type = ItemType.find_by(:name => "bar")

    self.items.build(
      :foo_id => self.id,
      :item_type_id => bar_item_type.id
    )
  end
end

class ItemsController
  def update
    bar_item_type = ItemType.find_by(:name => "bar")

    @item.update(:item_type_id => bar_item_type.id)
  end

end

在示例中,您可以看到我在Foo模型和ItemsController中都声明了bar_item_type变量。我想通过能够为Rails项目创建和访问一次该变量来干燥我的代码库,而不必到处进行相同的数据库调用。

2 个答案:

答案 0 :(得分:1)

我主张反对这种硬编码或DB状态相关的代码。如果必须这样做,这是我知道的方法之一:

# models
class ItemType < ActiveRecord::Base
  has_many :items

  # caches the value after first call
  def self.with_bar
    @@with_bar ||= transaction { find_or_create_by(name: "bar") }
  end

  def self.with_bar_id
    with_bar.id
  end
end

class Item < ActiveRecord::Base
  belongs_to :item_type
  belongs_to :foo

  scope :with_bar_types, -> { where(item_type_id: ItemType.with_bar_id) }
end

class Foo < ActiveRecord::Base
  has_many :items  

  # automatically sets the foo_id, no need to mention explicitly
  # the chained with_bar_types automatically sets the item_type_id to ItemType.with_bar_id
  def build_item
    self.items.with_bar_types.new
  end
end

# Controller
class ItemsController
  def update
    @item.update(item_type_id: ItemType.with_bar_id)
  end
end

答案 1 :(得分:0)

如果必须使用常量,则有几种方法可以使用它。但是必须考虑到要实例化一个ActiveRecord模型对象,该对象取决于数据库中存在的数据。不建议这样做,因为现在您具有依赖于数据库中存在的数据的模型和控制器逻辑。如果您已经为数据库设置了种子并且它不会更改,则可能没问题。

class ItemType
  BAR_TYPE ||= where(:name => "bar").limit(1).first 

  has_many :items
end

现在,您在任何需要此对象的地方都可以这样调用它:

bar_item_type  = ItemType::BAR_TYPE