I have user model and referral model. Referral model has user_id as field.
Now when a new user is created, I need to call referral#create as well and pass it the id of the newly generated user to user_id of referral model. How can I do that.
I have user model and referral model. Referral model has user_id as field.
Now when a new user is created, I need to call referral#create as well and pass it the id of the newly generated user to user_id of referral model. How can I do that.
I have user model and referral model. Referral model has user_id as field.
Now when a new user is created, I need to call referral#create as well and pass it the id of the newly generated user to user_id of referral model. How can I do that.
to answer what you said, in your User model, add the following
before_create :generate_referral
private def generate_referral self.referrals.create! {referral_attributes} end
There are better ways of solving this but I tried to convert your message into code in the most concise way possible
I would suggest to not setting the user_id field in the referral object
manually in your code, but use the built-in mechanisms for:
building the objects first in memory
saving the object with its associated objects in one “atomic” save.
If you set
class User < ActiveRecord::Base has_many :referrals end
You can do this:
$ rails c
Loading development environment (Rails 3.1.1.rc1)
001:0> u = User.new(:name => "Peter")
=> #
002:0> r1 = u.referrals.build(:comment => "sailor")
=> #
003:0> r2 = u.referrals.build(:comment => "developer")
=> #
004:0> u.save
(0.4ms) BEGIN
SQL (77.3ms) INSERT INTO "users" ("created_at", "name", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["created_at", Tue, 11 Oct 2011 10:56:14 UTC +00:00], ["name", "Peter"], ["updated_at", Tue, 11 Oct 2011 10:56:14 UTC +00:00]]
SQL (1.0ms) INSERT INTO "referrals" ("comment", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4) RETURNING "id" [["comment", "sailor"], ["created_at", Tue, 11 Oct 2011 10:56:14 UTC +00:00], ["updated_at", Tue, 11 Oct 2011 10:56:14 UTC +00:00], ["user_id", 2]]
SQL (0.4ms) INSERT INTO "referrals" ("comment", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4) RETURNING "id" [["comment", "developer"], ["created_at", Tue, 11 Oct 2011 10:56:14 UTC +00:00], ["updated_at", Tue, 11 Oct 2011 10:56:14 UTC +00:00], ["user_id", 2]]
(0.9ms) COMMIT
=> true
005:0> u
=> #
006:0> r1
=> #
007:0> r2
=> #
The magic is that you can add multiple referrals to the user in memory (without ever writing to
the database), and when you are fully done with preparing the user and the referrals, you do
one “atomic” save which will write all object to database (or none if it fails !).
To demonstrate that, I added to the referrals model a validation:
validates :comment, :presence => true
And make the validation fail:
$ rails c
Loading development environment (Rails 3.1.1.rc1)
001:0> u2 = User.new(:name => "Jan")
=> #
002:0> r1 = u2.referrals.build(:comment => "wanderer")
=> #
003:0> r2 = u2.referrals.build ### no comment here !
=> #
004:0> u2.save
(0.4ms) BEGIN
(0.4ms) ROLLBACK
=> false
005:0> User.find_by_name("Jan")
User Load (1.9ms) SELECT "users".* FROM "users" WHERE "users"."name" = 'Jan' LIMIT 1
=> nil
As you can see, nothing got saved, because I tried all saves in one “atomic” save.
HTH,
Peter
Hi!
Last month I was reading “Rails Antipatterns” and if I understood well, your situation fits with one described in the book:
The author says, in page 150:
“A presenter is simply a plain old Ruby class that orchestrates the creation of multiple models.”
I suggest you look for Active Presenter:
https://github.com/jamesgolick/active_presenter
Best Regards,
Everaldo
I had setup the associations, one to one, because that was the requirement
User Model has_one :referral
Referral Model belongs_to :user
and I also setup a "user_id" column in Referral model.
But what I did not know was about the magic call "BUILD"
Now I guess, all I have to do is
@user = User.new(:params[:user]) @user.referral.build @user.save
Hi Nikhil,
A few hints.
as I do here (as opposed to “top quoting”)
“4.2 has_one Association Reference” of http://guides.rubyonrails.org/association_basics.html
@user.build_referral # untested
HTH,
Peter
Peter Vandenabeele wrote in post #1026116:
* actually, I believe what you propose above will not work, it would probably be
@user.build_referral # untested
Actually, your believe isn't accurate. You should have tested. ![]()
See collection.build and collection.create explained here:
Robert Walker wrote in post #1026165:
Peter Vandenabeele wrote in post #1026116:
* actually, I believe what you propose above will not work, it would probably be
@user.build_referral # untested
Actually, your believe isn't accurate. You should have tested.
See collection.build and collection.create explained here:
Sorry, I just realized that is is a has_one rather than has_many, so please disregard previous reply.
* you can find all details about these association methods in section "4.2 has_one Association Reference" ofhttp://guides.rubyonrails.org/association_basics.html * actually, I believe what you propose above will not work, it would probably be
@user.build_referral # untested
You were absolutely right, @user.build_referral works, I have tested it and it has been clearly mentioned in the rubyonrails guides.
@user.referral.build
would have worked only if the association was of the type has_many or has_and_belongs_to_many
No prob. In reference to
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
I have always been curious why the format of the association methods
is so different for the singular compared to collection associations. This then
leads to confusion as shown above …
has_many => self.others.xxx (many methods added by has_many)
has_one => self.{build|create}_other
Maybe for the singular association, we could add
self.other.build
self.other.create
self.other.create!
to make it more uniform ?
HTH,
Peter
Has_one is very similar to has_many, in sense, but rails does a LIMIT to 1 when we use has_one. In essence, its a good way to differentiate that we are using has_one or has_many.
Thats my understanding and opinion.
Regards Nikhil