Add association (<<) without committing to database

前端 未结 4 911
挽巷
挽巷 2021-02-05 04:21

Is it possible in Rails to add an association to an existing record without immediately committing this change to the database? E.g. if I have Post has_many :ta

相关标签:
4条回答
  • 2021-02-05 05:06
    post_tag = post.post_tags.find_or_initialize_by_tag_id(Tag.first.id)
    post_tag.save
    
    0 讨论(0)
  • 2021-02-05 05:08

    This should work in Rails 3.2 and Rails 4:

    post.association(:tags).add_to_target(Tag.first)
    

    See this gist: https://gist.github.com/betesh/dd97a331f67736d8b83a

    Note that saving the parent saves the child and that child.parent_id is NOT set until you save it.

    EDIT 12/6/2015: For a polymorphic record:

    post.association(:tags).send(:build_through_record, Tag.first)
    # Tested in Rails 4.2.5
    
    0 讨论(0)
  • 2021-02-05 05:16

    PREFACE This is not exactly an answer to this question but somebody searching for this kind of functionality may find this useful. Consider this and other options very carefully before wantonly putting it into a production environment.

    You can, in some cases, leverage a has_one relationship to get what you want. Again, really consider what you're trying to accomplish before you use this.

    Code to Consider You have a has_many relationship from Trunk to Branch and you want to add a new branch.

    class Trunk
      has_many :branches
    end
    
    class Branch
      belongs_to :trunk
    end
    

    I can also relate them to each other singularly. We'll add a has_one relationship to the Trunk

    class Trunk
      has_many :branches
      has_one :branch
    end
    

    At this point, you can do things like Tree.new.branch = Branch.new and you'll be setting up a relationship that will not save immediately, but, after saving, will be available from Tree.first.branches.

    However, this makes for quite a confusing situation for new developers when they look at the code and think, "Well, which the hell is it supposed to be, one or many?"

    To address this, we can make a more reasonable has_one relationship with a scope.

    class Trunk
      has_many :branches
    
      # Using timestamps
      has_one :newest_branch, -> { newest }, class_name: 'Branch'
    
      # Alternative, using ID. Side note, avoid the railsy word "last"
      has_one :aftmost_branch, -> { aftmost }, class_name: 'Branch'
    end
    
    class Branch
      belongs_to :trunk
    
      scope :newest, -> { order created_at: :desc }
      scope :aftmost, -> { order id: :desc }
    end
    

    Be careful with this, but it can accomplish the functionality being asked for in the OP.

    0 讨论(0)
  • 2021-02-05 05:18

    To add to Isaac's answer, post.association(:tags).add_to_target(Tag.first) works for has_many relationships, but you can use post.association(:tag).replace(Tag.first, false) for has_one relationships. The second argument (false) tells it not to save; it will commit it to the database by default if you leave the argument empty.

    0 讨论(0)
提交回复
热议问题