在Rails

时间:2018-01-18 21:06:26

标签: ruby-on-rails activerecord rails-activerecord

是否有可能在通过关联找到的记录中保留对找到它的相关模型实例的访问权限?

示例:

class Person < ApplicationRecord
  has_many :assignments
  attr_accessor :info_of_the_moment
end

p = Person.first
p.info_of_the_moment = "I don't want this in the db"
assignment = p.assignments.first
assignment.somehow_get_p.info_of_the_moment # or some such magic!

和/或有没有办法“挂起”作用域的参数并从找到的模型实例中访问它们?像:

class Person < ApplicationRecord
  has_many :assignments
  attr_accessor :info_of_the_moment
  scope :fun_assignments, -> (info) { where(fun: true) }
end

class Assignment < ApplicationRecord
  belongs_to :person

  def get_original_info
    # When I was found, info was passed into the scope. What was it?
  end
end

1 个答案:

答案 0 :(得分:0)

您可以将自己的扩展方法添加到关联中,这些方法可以通过proxy_association获取关联所有者:

has_many :things do
  def m
    # Look at proxy_association.owner in here
  end
end

所以你可以这样说:

class Person < ApplicationRecord
  has_many :assignments do
    def with_info
      info = proxy_association.owner.info_of_the_moment
      # Then we wave our hands and some magic happens to encode
      # `info` into a properly escaped SQL literal that we can
      # toss in a `select` call. If you're working with PostgreSQL
      # then JSON would be a reasonable first choice if the info
      # was, say, a hash.
      #
      # The `::jsonb` in the `select` call is there to tell everyone
      # that the `info_of_the_moment` column is JSON and should be
      # decoded as such by ActiveRecord.
      encoded_info = ApplicationRecord.connection.quote(info.to_json)
      select("assignments.*, #{encoded_info}::jsonb as info_of_the_moment")
    end
  end
  #...
end

p = Person.first
p.info_of_the_moment = { 'some hash' => 'that does', 'not go in' => 'the database' }
assignment = p.assignments.with_info.first
assignment.info_of_the_moment # And out comes the hash but with stringified keys regardless of the original format.

# These will also include the `info_of_the_moment`
p.assignments.where(...).with_info
p.assignments.with_info.where(...)

注意事项:

  • select中的所有列都显示为方法,即使它们不属于相关表格的一部分。
  • 您可以通过在调用关联方法时使用这些方法包含块来向关联添加“扩展”方法。
  • SQL SELECT可以包含非列的值,文字也可以正常工作。
  • 用于通过关联挖掘额外信息的格式取决于底层数据库。
  • 如果编码的额外信息很大,那么这可能会很昂贵。

这无疑是有点笨拙和脆弱的,所以我同意你的观点,重新思考你的整个方法是一个更好的主意。