I wonder id it is normal behaviour that when building an assosiation ‘build’ method , the returned size of association array changes despite the objet is nt saved yet ? Here is a short exampe to illustrate that:
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
end
class Post < ActiveRecord::Base
belongs_to :user
end
``
Nothing complex until now. When I play with that in the console:
Loading development environment (Rails 4.2.0)
irb(main):001:0> user = User.first
User Load (0.0ms) SELECT “users”.* FROM “users” ORDER BY “users”.“id” ASC LIMIT 1
=> #<User id: 1, name: “toto”, created_at: “2015-01-16 11:18:41”, updated_at: “2015-01-16 11:18:41”>
irb(main):002:0> user.posts.size
(0.0ms) SELECT COUNT(*) FROM “posts” WHERE “posts”.“user_id” = ? [[“user_id”, 1]]
=> 0
irb(main):003:0> post = user.posts.build(title: ‘ruby’)
=> #<Post id: nil, user_id: 1, title: “ruby”, created_at: nil, updated_at: nil>
irb(main):004:0> user.posts.size
=> 1
irb(main):005:0>
``
As you see the size of user posts is changed by 1. Why ? The post is not still saved to the database. The user_id is nil. I had to apply some validation before adding a new post tp ths user, that’s why I wonder if it is normal adn how to display just the existing User posts without using ‘select’ for example.
Rails version: 4.2.0, Ruby 2.1.5
You have not saved it to the database but you have added it to the
users posts in memory. If you reload user it will revert to 0, and
you will lose the built post. If you want to check what it is in the
database then fetch the user to a new variable.
user1 = User.first
then user1.posts.size will be 0
So it is normal because AR does not make a new query to the DB and operates on the existing cached collection. What if instead of making the same query to find the same user:
user1 = User.first
``
I’ll do like that:
user.posts(force_reload: true).size
``
it works as needed and it seems like force_reload is false by default. What do you think ?
I think just user.reload would do it. It is not something I have had
to do often, why would one build an association and then want to throw
it away again in the same action?
As you see the size of user posts is changed by 1. Why ? The post is not
still saved to the database. The user_id is nil. I had to apply some
validation before adding a new post tp ths user, that’s why I wonder if
it
is normal adn how to display just the existing User posts without using
‘select’ for example.
You have not saved it to the database but you have added it to the
users posts in memory. If you reload user it will revert to 0, and
you will lose the built post. If you want to check what it is in the
database then fetch the user to a new variable.
user1 = User.first
then user1.posts.size will be 0
Colin
So it is normal because AR does not make a new query to the DB and operates
on the existing cached collection. What if instead of making the same query
to find the same user:
user1 = User.first
I’ll do like that:
user.posts(force_reload: true).size
it works as needed and it seems like force_reload is false by default. What
do you think ?
I think just user.reload would do it. It is not something I have had
to do often, why would one build an association and then want to throw
it away again in the same action?
Why do I want it - because I’d like to run a validation callback before saving an element of the collection. For example, an Account has_many Operations. So I create an Operation like that in the OperationsController:
def create
@operation = @account.operations.new(operation_params)
if @operation.save
redirect_to @account, notice: t(:created_success, model: Operation.model_name.human)
else
render “new”
end
end
What I’d like to do is to check the sum to be withdrawn in the above operation so that the balance of the account not to be negative. That’s how I
discovered the described behaviour.