NNNNNNNNNNDelicious
NNNNNNNNNNDelicious

Reputation: 983

Setting a 'has_many's object to carry it's parent id

I have an object called a tag which has_many :tweets. The tweet also has a corresponding belongs_to.

If I'm generating a tweet to save in the tag model like so:

        new_tweet = Tweet.new

        new_tweet.favorite_count = tweet.favorite_count 
        new_tweet.filter_level = tweet.filter_level 
        new_tweet.retweet_count = tweet.retweet_count 
        new_tweet.text = tweet.text 
        new_tweet.tweeted_at = tweet.created_at 

        new_tweet.created_at = DateTime.strptime tweet.created_at.to_s, '%Y-%m-%d %H:%M:%S %z' 

        new_tweet.save 

How do I set that tweets parent to be the current tag? Would I do something like this?

new_tweet.tag = self

I tried this and it didn't work, whats a better solution? Thanks for your help.

Upvotes: 1

Views: 87

Answers (3)

Nitin
Nitin

Reputation: 7366

Try create tweet's new object with association and tag_id will automatically assign in your new tweet object. So change Tweet.new to self.tweets.new and you are done.

new_tweet = self.tweets.new

new_tweet.favorite_count = tweet.favorite_count 
new_tweet.filter_level = tweet.filter_level 
new_tweet.retweet_count = tweet.retweet_count 
new_tweet.text = tweet.text 
new_tweet.tweeted_at = tweet.created_at 

new_tweet.created_at = DateTime.strptime tweet.created_at.to_s, '%Y-%m-%d %H:%M:%S %z' 

new_tweet.save 

As per your comment. You also have database structure issue. You need to resolve that first. You don't have tag_id in your tweets table assuming you take tag name column. To make my code work properly and create a proper parent child relation you must have parent_id in your child table.

So try add tag_id in your tweets table and your error will gone. Also your value will save properly.

Upvotes: 1

Richard Peck
Richard Peck

Reputation: 76784

I think there's a better way to do it.

If you're saving a tag object, why not just use an after_create hook to make another tweet? You're basically copying all the data over anyway...

For example:

#app/models/tag.rb
class Tag < ActiveRecord::Base
    has_many :tweets
    attr_accessor :parent
    #This will allow you to save a tag with attribute "parent" as true. If true, the tweet model will create another tweet. It will need tweaking
end

#app/models/tweet.rb
class Tweet < ActiveRecord::Base
   belongs_to :tag
   after_create :new_tweet, if: Proc.new { |tweet| tweet.tag.parent }

   def new_tweet
      new = self.clone
      new.tweeted_at = self.created_at
      new.created_at = DateTime.strptime self.created_at.to_s, '%Y-%m-%d %H:%M:%S %z' 
      new.save
   end
end

You can read more about Rails' clone method here.

--

Relational

Rails is actually very good with handling relational data.

Pavan in the comments is almost spot-on with his recommendation of using tag_id. This, of course, will load a database attribute, but there's a better way.

As can be seen here, there are a number of methods added with a has_many/belongs_to relationship:

enter image description here

enter image description here

This means you'll be able to use the following:

  • tweet.tag to retrieve the tag object.

  • If tweet had many tag, you'd be able to use the tweet.tag or tweet.tag_id

All of this means you can pass an object to your new_tweet.tag attribute...

Thus, your answer:

new_tweet.tag = tweet.tag

Upvotes: 0

LapinLove404
LapinLove404

Reputation: 1949

I'd say you have two solutions :

1) As suggested by pavan, assign the tag_id of the original tweet to the new tag. This will create the association between new_tweet and the tag :

new_tweet.tag_id = tweet.tag_id

2) Or, if you do create the new_tweet in a tag instance method, you can directly create the tweet through the association as suggested by Dipak :

new_tweet = self.tweets.build

Upvotes: 0

Related Questions