Ruby on Rails和类变量混淆

时间:2014-08-13 03:55:05

标签: ruby-on-rails ruby oop ruby-on-rails-4 class-variables

我在Rails中有一个枚举属性为“status”的模型。我希望有一个公共和私人状态的概念,如下所示:

class Something < ActiveRecord::Base
  @public_statuses = [:open, :closed, :current]
  @private_statuses = [:deleted]

  enum status: @public_statuses + @private_statuses
end

这样我就可以在视图中执行以下操作:

<select>

<% Something.public_statuses.each do |status| %>
    <option value="<%= status %>"><%= status.humanize %></option>
<% end %>

</select>

这样,我不会将私有状态暴露给最终用户。

不幸的是,我不太了解Ruby类,无论我是否使用@public_statuses,@@ public_statuses,public_statuses = [...]等,我都无法使用它。我熟悉Java和其他OO语言,但在这里不知道如何做Ruby。

这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

您可以将变量视为类方法,并将您想要访问的变量定义为私有(在Ruby中并非绝对正确)。像:

    def self.public_statuses
        [:open, :closed, :current]
    end

    def self.private_statuses
        [:deleted]
    end

    private_class_method :private_statuses

但是如果你真的要使用变量,在这种情况下,常量,那就非常相似:

PUBLIC_STATUSES = [:open, :closed, :current]
PRIVATE_STATUSES = [:deleted]
private_constant :PRIVATE_STATUSES

所以,你可以使用它:

puts Something::PUBLIC_STATUSES
=> [:open, :closed, :current]
puts Something::PRIVATE_STATUSES
NameError: private constant Client::PRIVATE_STATUSES referenced

答案 1 :(得分:1)

您所做的是定义了两个实例变量而不是类变量,因此将它们作为Foo.instance_variable访问是行不通的。您需要Foo的实例才能访问它们。因此,您可以使用以下内容替换每个块的视图:

<% Something.new.public_statuses.each do |status| %>
  <option value="<%= status %>"><%= status.humanize %></option>
<% end %>

在这里,您实例化Something,然后在该实例上调用pubic_statuses.each。所以这对你有用。

但是,如果您想将它们用作类变量,那么您需要在模型类中添加类访问器方法:

class Something < ActiveRecord::Base
  @@public_statuses = [:open, :closed, :current]
  @private_statuses = [:deleted]

  enum status: public_statuses + @private_statuses


  def self.public_statuses
    @@public_statuses
  end
end

在使用Rails时,您还可以定义cattr_reader :public_statuses,而不是上面代码中定义的getter方法。使用这些添加类方法的选项,您无需更改视图。

另一种选择是使它们成为常量:

class Something < ActiveRecord::Base
  PUBLIC_STATUSES = [:open, :closed, :current]
  PRIVATE_STATUSES = [:deleted]

  enum status: PUBLIC_STATUSES + PRIVATE_STATUSES
end

然后在你看来:

<% Something::PUBLIC_STATUSES.each do |status| %>