简体   繁体   中英

Change model attribute in ActiveRecord in Ruby on Rails

class Person < ActiveRecord::Base
  belongs_to :parent, class_name: 'Person'
  has_many :children, class_name: 'Person', foreign_key: :parent_id
  has_many :grandchildren, class_name: 'Person', through: :children, source: :children
end

I want this model to work that way (doesn't matter how):

grandfather = Person.create(name: "Grandfather")
father = Person.create(name: "Father", parent: grandfather)
son = Person.create(name: "Son", parent: father)

grandfather.children.map(&:name)
=> ['father']
grandfather.grandchildren.map(&:name)
=> ['Son']

So the idea is to get children's name downcased. I can use callbacks or override getter of name attribute, but this apply to both children and grandchildren, so that's not the point.

I can guess that task is in adding a knowledge about record being a "son", but not a "grandson". So you have a directional tree, and need to know each node's depth:

class Person < ActiveRecord::Base
...
  def depth
    (parent&.depth || 0) + 1
  end

  def name
    if depth == 2
      super.downcase
    else
      super
    end
  end
end

Note that this is not efficient for large data structures with deep nesting, there it's better to materialise this into additional attribute that should be calculated upon setting parent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM