1

I have 2 models like the following


    Class Post  
      has_many :comments, :dependent => :destroy 
    end  

    Class Comment  
      validates_presence_of :post
      validates_presence_of :comment
      belongs_to :post  
    end  
  

In Comments controller,


    def create
      comment = @post.comments.build(params[:comment])
      if comment.save
        // some code
      else
        // some code
      end
    end

When the comment is invalid as per the validation, the comment is not saved. But when the @post object is accessed in the view, it contains a comment object with nil id. This did not happen in Rails 2.3.11. We are upgraded to Rails 3.1 and then now to Rails 3.2. This comment object with nil id disappears when I do @post.reload. We are using REE.

I tried to interchange build and new methods. It had the same result as build. Similar behavior is found across our application. Is it the expected behavior or am I doing something wrong?

2 Answers 2

2

This seems like expected behaviour to me.

via http://guides.rubyonrails.org/association_basics.html#belongs_to-association-reference

4.1.1.3 build_association(attributes = {})

The build_association method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through this object’s foreign key will be set, but the associated object will not yet be saved.

When you call @post.comments.build(...), Rails:

  1. Creates a new Comment object
  2. sets comment.post_id to @post.id.
  3. Inserts it into the comments array (in memory).

When the validation fails, it doesn't delete the comment and the comment persists in the in-memory comments array. When @post gets to your view, @post.comments still includes that badly validated comment.

As for how to deal with it, I'm not sure. Maybe you could do something like (in your controller)... (Feels pretty ugly though.)

def create
  comment = @post.comments.build(params[:comment])
  if comment.save
    // some code
  else
    @bad_comment = @post.comments.pop
  end
end
Sign up to request clarification or add additional context in comments.

1 Comment

Apparently there is no difference between build and new methods from rails 3.1. So I think this is the expected behavior. github.com/rails/rails/issues/7229
0

I had a similar problem while using rails 3.2

Firstly, you need to create two separate methods in your controller. They will be as follows:

  1. The 'new' method that is used to build your comments using 'build_association'

    def new
        @post = Post.new
        comment = @post.build_comments
    end
    
  2. The 'create' method to actually create your comments using 'create_association'

    def create 
        @post = Post.new(params[:post])
        comment = @post.create_comments(params[:post][:comment_attributes])
    
        if comment.save
            // some code
        else
            @bad_comment = @post.comments.pop
        end
    end
    

Note: I suggest passing 'comment' attribute as a nested attribute of 'post' through your form using 'fields_for'.

Please refer: http://apidock.com/rails/ActionView/Helpers/FormHelper/fields_for

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.