Rails - serialize another activerecord model - ruby-on-rails

I'm looking to serialize an incomplete/temporary model as an attribute of another model such as:
class User < ActiveRecord::Base
serialize :pending_post
end
Where pending_post is assigned an activerecord model:
...
user.pending_post = Post.new(:title => "Whatever", :message => "whatever")
user.save
But instead of saving the yaml for the new Post model, the pending_post attribute is nil (in the DB and on reload). The serialize works great with other objects, Hashes, Arrays, etc, but comes up nil in this case. This is Rails 2.3.9, but I did a quick test with 3.0.1 and saw the same results. I found this description of the issue from years ago: http://www.ruby-forum.com/topic/101858.
I know I could manually serialize/deserialize the object (which works fine) or serialize just the post.attributes, but I'm curious if anyone knows why this acts as it does? It seems if the new post is saved before being assigned to user.pending_post, then just the ID is saved as the user.pending_post attribute. I'm pretty sure it's intentional and not a bug, but I quite don't understand the reasoning. Is it poor form to serialize an active_record model?

I think you need to serialize/save the attributes, not the post object itself, like so:
user.pending_post = {:title => 'Whatever', :message => 'whatever'}
user.save
Then later you can turn it into a real post:
user.posts.create user.pending_post
And I'd probably take it a step further (as I so often do) with a user method:
def save_post
self.posts.create self.pending_post
end
I hope this helps!

Related

Retrieve a tree from database and convert it to json with Rails

I have a table with nested comments and they have comment_id field to point to parent comment. I put has_many :comments, :class_name => "Comment" in comment's model and so i have a tree. The question is how with all power of Rails and ActiveRecord i can get whole comments tree from database and respond with it in json format? I know about ancestry
but i want to find solution without any side gems. I want to learn best ways in Rails for manipulation tree-like structures because this task will appear again and again in my further practice.
UPDATE:
I found some related question here and used answer from it. I define method in model
def self.get_tree(comments)
comments.map { |comment|
{:responses => get_tree(comment.comments), :user => comment.user, :text => comment.text}
}
end
and then just call it to get whole tree (with some conditions)
render :json => Comment.get_tree(Comment
.where('announce_id = ?', params[:id])
.where('comment_id is NULL'))
With this implementation i clearly see now that there no need in side gems for this task. But also in current implementation i should list all comment's properties inside map. Are there any way to just extend existing object with {:responses => get_tree(comment.comments), :user => comment.user}? I
found << for arrays and .update for hashes but then i ended up with that i have no idea whatcomment inside map block is. Either it array or hash or object...

Serialized object works fine on my dev box, Heroku gives "TypeError (can't dump anonymous class Class)"

I may be using serialized objects wrong, so I apologize in advance. For an activity feed, I'm using a serialized meta-data column to simplify the database call. E.g. for the activity feed, I'm just pulling in Activity objects with the appropriate user_id. I'm adding in the line_item object as seen here:
class Activity < ActiveRecord::Base
serialize :data
activity = Activity.new(:user_id => user_id...)
if activity.source_type == "LineItem"
line_item = LineItem.find(activity.source_id)
activity.update_attributes(:data => line_item)
end
Then I call it via some partials where "book" is the meta-data bit:
= link_to image_tag(item.data.book.image_url),
book_path(item.data.book.id)
This works fine on my box, but Heroku gives me "TypeError (can't dump anonymous class Class)". What gives?
I think you need to explicitly say what type you are serializing to. So the syntax would be:
serialize :data, Hash

Why are my associations not rendered to JSON?

I'm trying to control the JSON rendering of a user object in Rails 3.0.2. Here's the relevant model code:
class User < ActiveRecord::Base
belongs_to :employer
has_and_belongs_to_many :roles
def as_json(options={})
super(options.merge(:include => [:employer, :roles]))
end
end
Here's the JSON representation I get:
{"user":{"employer":{},"roles":[{},{},{}],"email":"user.user#example.com"}}
This user does have three roles, so somehow the :include statement is looking up the association, but the role and employer objects are not getting converted to JSON.
If I had an as_json to either of those models, returning garbage, it still doesn't show up.
Am I doing something wrong, or is this a bug? (It wasn't rendering anything for the associations until I upgraded from Rails 3.0.0, which I learned to do from this question.)
You can try:
to_json(:include => [:employer, :roles]) in place of as_json
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html
My workaround
I'm still not sure why it didn't work, but my workaround is to build the representation I wanted manually.
def serializable_hash(options={})
hash_info = super(options)
hash_info[:employer] = {:name => employer.name}
hash_info[:roles] = roles
hash_info
end
I'm using serializable_hash because that is a more general-purpose method from which Rails can generate JSON or XML or whatever. But the method works the same if you change the name to as_json.

How do I manually set nested model values in Rails 3 before saving?

I have a single text area input that I would like to get as a blob my new method on my controller, but would like to parse and otherwise mess with the input before it's saved.
I know I can arbitrarily set attributes on a model by saying something like
#post.user_id = current_user.id
where that attribute isn't coming directly from a form. My issue here though is that I want to set a nested model's values.
Let's say the association is post has_many comments and comment belongs_to post
Does post.comments just get set to a hash that looks like comments? Like
#post.comment = {'comment' => 'foo'}
Or something similar?
Thanks for any guidance on this.
Usually I'd say it's best to DRY up this sort of thing and just handle the parsing on the comments model itself with a before_save callback.
class Comment < ActiveRecord::Base
before_save :parse_comment
protected
def parse_comment
self.comment = ...
end
end
But if a callback isn't going to work for you, #corroded's suggestion should work.
if you have nested form fors, you can just get the comment values from your params via:
#post.comment.update_attributes(params[:comment])
(you should have called #post.build_comment in your #new though)
If you're looking to set them in your controller, then you need a hash 'container' for your comment like so:
{'comment' => {:message => 'foo', :author => current_user}}
or something like that

Rails: How can I access the parent model of a new record's nested associations?

Suppose we have the standard Post & Comment models, with Post having accepts_nested_attributes_for :commments and :autosave => true set.
We can create a new post together with some new comments, e.g.:
#post = Post.new :subject => 'foo'
#post.comments.build :text => 'bar'
#post.comments.first # returns the new comment 'bar'
#post.comments.first.post # returns nil :(
#post.save # saves both post and comments simultaneously, in a transaction etc
#post.comments.first # returns the comment 'bar'
#post.comments.first.post # returns the post 'foo'
However, I need to be able to distinguish from within Comment (e.g. from its before_save or validation functions) between
this comment is not attached to a post (which is invalid)
this comment is attached to an unsaved post (which is valid)
Unfortunately, merely calling self.post from Comment doesn't work, because per above, it returns nil until after save happens. In a callback of course, I don't (and shouldn't) have access to #post, only to self of the comment in question.
So: how can I access the parent model of a new record's nested associations, from the perspective of that nested association model?
(FWIW, the actual sample I'm using this with allows people to create a naked "comment" and will then automatically create a "post" to contain it if there isn't one already. I've simplified this example so it's not specific to my code in irrelevant ways.)
I think it is strange that Rails does not let you do this. It also affects validations in the child model.
There's a ticket with much discussion and no resolution in the Rails bug tracker about this:
Nested attributes validations
circular
dependency
And a proposed resolution:
nested models: build should directly
assign the
parent
Basically, the deal is, the nested attributes code doesn't set the parent association in the child record.
There's some work-arounds mentioned in the second ticket I linked to.
I don't think you can do this. On the other hand, your validations shouldn't be failing, as the order of the transaction will create the post record before saving the comment.

Resources