Rails选择值为属性

时间:2016-02-16 02:48:31

标签: ruby-on-rails ruby activerecord

假设我有一个这样的简单模型,名为“name”的字段和名为“aliased_name”的属性:

class User < ActiveRecord::Base
   attr_accessor :aliased_name
end

User.create(name: "Faye Kname")

我能做到:

user=User.select(:id, :name)
user.name # Faye Kname

但是如何使用select填充aliased_name属性。

user=User.select(:id, "name AS aliased_name")
user.aliased_name # nil
user[:aliased_name] # Faye Kname

我可以访问:aliased_name符号,但未分配该属性。我不想做

user.aliased_name = user[:aliased_name]

我实际上正在另一个表上进行更复杂的连接,我正在尝试从连接表中选择一个字段到别名中,但我认为这是一个更简单的例子。

3 个答案:

答案 0 :(得分:3)

通常,我使用方法而不是attr_accessors来执行这些别名。像

这样的东西
def aliased_name
  has_attribute?(:aliased_name) ? read_attribute(:aliased_name) : self.name
end

如果您没有在查询中加载属性,has_attribute?就会存在,因此您可以使用默认值。

答案 1 :(得分:1)

所以attr_accessor正在寻找我认为你的代码中没有设置的实例变量@aliased_name。您可以使用@aliased_name = "some value"或使用attr_accessor aliased_name = "some value"进行设置,但不会使用返回对象的初始查询进行设置,也不会在第二个SELECT查询中进行设置,至少在现在编写它时。

可能有意义的一条路线是使用单独的方法和attr_writer。像这样的东西

    attr_writer :aliased_name

    def aliased_name
      @aliased_name ||= self.name
    end

这会在第一次调用时设置实例变量,并让您可以使用attr_writer自由更改它。我不确定这是如何适应更复杂的连接,但这是解决您最初描述的问题的一种相当简单的方法。

答案 2 :(得分:1)

您最好使用alias_attribute

#app/models/user.rb
class User < ActiveRecord::Base
  alias_attribute :aliased_name, :name
end

虽然只需要user.name数据&amp;把它放进user.alias_attribute

  

我试图从连接表中选择一个字段到别名

之前完成此事:

您有两种选择。使用SQL ALIAS列,或访问模型中的proxy_association方法。我与两者都进行了广泛的合作:

-

SQL别名

#app/models/parent.rb
class Parent < ActiveRecord::Base
  has_many :joins
  has_many :children, -> { select("#{Parent.table_name}.*, #{Join.table_name}.attr AS alias_name") }, through: :joins, dependent: :destroy
end

这会给你......

@parent.children.each do |child|
  child.alias_name
end

-

Association Extensions

下一个方法要复杂得多;效率更高:

#app/models/parent.rb
class Parent < ActiveRecord::Base
   has_many :joins
   has_many :children, through: :joins, -> { extending AliasAttribute }
end

#app/models/concerns/alias_attribute.rb
module PlayerPermission

        #Load
        def load
          alias_names.each do |permission|
              proxy_association.target << permission
          end
        end

        #Private
        private

        #Names
        def names
           return_array = []
           through_collection.each_with_index do |through,i|
              associate = through.send(reflection_name)
              associate.assign_attributes({name: items[i]})
              return_array.concat Array.new(1).fill( associate )
           end
           return_array
        end

        #######################
        #      Variables      #
        #######################

        #Association
        def reflection_name
           proxy_association.source_reflection.name
        end

        #Foreign Key
        def through_source_key
           proxy_association.reflection.source_reflection.foreign_key
        end

        #Primary Key
        def through_primary_key
           proxy_association.reflection.through_reflection.active_record_primary_key
        end

        #Through Name
        def through_name
           proxy_association.reflection.through_reflection.name
        end

        #Through
        def through_collection
           proxy_association.owner.send through_name
        end

        #Captions
        def items
            through_collection.map(&:name)
        end

        #Target
        def target_collection
            #load_target
            proxy_association.target
        end

end

每次调用关联时,您都可以访问.association对象。在关联本身内,您可以访问proxy_association个对象;所有这些操作都可以将别名数据插入到父数据中。

以上将允许您使用:

@parent = Parent.find x
@parent.children.each do |child|
  child.alias_name
end 

如果需要,我可以提供支持。