Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
215 views
in Technique[技术] by (71.8m points)

Rails setter method that updates two other fields?

Background

I have some polymorphic relationships - one in particular assetable where I have a parent-child Asset relationship and the parent has various classes.

I also have a global Tracker model that creates a global id type scheme across my various models which I also use the FriendlyID gem for.

My Goal

Something like this:

parent = Tracker.find_by(tracker: '4Q73XEGK').trackable
Asset.find(1).update(parent_tracker: parent.tracker_id)

thinking I could do something like this - set the new polymorphic relationship by the tracker_id:

  class Asset < ActiveRecord::Base

    def parent_tracker
      assetable.tracker_id
    end
       
    def parent_tracker=(val)
       
      a = Tracker.find_by(tracker: val).trackable
        
      assetable_id = a.id
      assetable_type = a.class.name
        
    end
   end

Question?

Am I on the right path here (with tweaks) OR show that I am on the completely wrong path here.

I know that there are before_save filters etc. but the setter approach seems more elegant and clear as I can apply this across many other models.

question from:https://stackoverflow.com/questions/65894825/rails-setter-method-that-updates-two-other-fields

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You should not have to set both the type and id - use the setter created by the association instead:

class Asset < ActiveRecord::Base
  belongs_to :assetable, polymorphic: true

  def parent_tracker
    assetable.tracker_id
  end
   
  def parent_tracker=(val)
    self.assetable = Tracker.find_by(tracker: val).trackable
  end
end

The setter for polymorphic associations will set both the id and type attributes. Also note that you need to use self explicitly when calling setters.

assetable_id = a.id
assetable_type = a.class.name

Will just set local variables that are garbage collected when the method ends.

Tracker.find_by(tracker: val) feels really smelly too. If your Tracker class just keeps track of global ids shouldn't it provide a method that takes such an id and returns the trackable?

class Tracker < ActiveRecord::Base
  def self.lookup(global_id)
    find_by(tracker: global_id).trackable
  end
end

class Asset < ActiveRecord::Base
  belongs_to :assetable, polymorphic: true
  # ...

  def parent_tracker=(val)
    self.assetable = Tracker.lookup(val)
  end
end

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...