Multiple feature creation.

Hi all I wondering how I would go about generating multiple features on user creation. I want every user who signs up to have a wishlist automatically which is a separate to the actual users (different model/view/controller etc.)

On user create I want it to create a user as well as create a wishlist. The wishlist will be blank but I just want the feature to show on their profile so that they can edit. Currently the user has to click on a button to set it up.

Here is my current user create method. I want to add a line to create the wishlist alongside. Any help will be appreciated.

def create   @user = User.new(params[:user])   respond_to do |format|     if @user.save       UserMailer.registration_confirmation(@user).deliver       session[:user_id] = @user.id       format.html { redirect_to root_url, :notice => "User was successfully created." }

    else       format.html { render :action => "new" }       format.xml { render :xml => @user.errors, :status => :unprocessable_entity }     end   end end

Hi Chris,

Use an after_create callback in the User model to create the associated Wishlist record.

HTH, Bill

Use an after_create callback in the User model to create the associated Wishlist record.

So in the user model would I define first like this:

after_create :set_wishlist

then the following:

def set_wishlist @wishlist = Wishlist.new(params[:wishlist]) end

I hope I am on the correct track.

Any feedback would be great. Thanks.

That's the general idea though, from what you've said, the only thing you'll know about the Wishlist object at the point of creation is the User to whom it belongs. If you need to return it to the user in the response, as indicated by your creation of a separate instance variable, you'll want to do that in the User controller prior to rendering.

Best regards, Bill

Hi,

I tried the method that I stated in the model:

def set_wishlist @wishlist = Wishlist.new(params[:wishlist]) end

But once I created the user it returned an error screen stating:

NameError in UsersController#create

undefined local variable or method `params' for #<User:0x4a51a78> Rails.root: C:/finalproject

Application Trace | Framework Trace | Full Trace

app/models/user.rb:21:in `set_wishlist' app/controllers/users_controller.rb:35:in `block in create' app/controllers/users_controller.rb:34:in `create'

My usersController create methods looks like the following:

def create   @user = User.new(params[:user])   respond_to do |format|     if @user.save       UserMailer.registration_confirmation(@user).deliver       session[:user_id] = @user.id       format.html { redirect_to root_url, :notice => "User was successfully created." }

    else       format.html { render :action => "new" }       format.xml { render :xml => @user.errors, :status => :unprocessable_entity }     end   end end

Hi,

I tried the method that I stated in the model:

def set_wishlist @wishlist = Wishlist.new(params[:wishlist]) end

But once I created the user it returned an error screen stating:

NameError in UsersController#create

undefined local variable or method `params' for #<User:0x4a51a78> Rails.root: C:/finalproject

If you tried this in the controller, you would find the params hash available. But in the model, there's no such animal. That's what the error message is telling you. You could pass that variable back to the model, like this:

def set_wishlist(params) ... end

and then include the params hash in your method call. But if you want to rely on that hash just being there, you could probably put this method in your controller and call it from there in your after_create callback.

Walter

By stating params in the model as

def set_wishlist(params)

It returns the error of: wrong number of arguments (0 of 1).

If I was to try and call the create method from wishlistController through the user model, how would I go about calling it?

I have not had he experience of doing such thing before.

Thanks Chris.

By stating params in the model as

def set_wishlist(params)

It returns the error of: wrong number of arguments (0 of 1).

If I was to try and call the create method from wishlistController through the user model, how would I go about calling it?

I have not had he experience of doing such thing before.

I don't think you can, but you can do an after_filter on create, in the controller:

  after_filter :foo, :only => :create ...   private   def foo     @word.update_attributes(:notes => 'FOO!')   end

I just did this and it worked. You would have access to the variables you set in your create method. Apparently these after_filter beasties fire before any redirect is called.

Walter

Hey Walter,

I have the following in my userController

after_filter :set_wishlist, :only => :create

  def set_wishlist     @wishlist = Wishlist.new(params[:wishlist])     @wishlist.user = current_user   end

It goes ahead but doesn't actually create a wishlist for the user. I checked in the server log and it seems to just be searching for any wishlist matching this user which it obviously wont find because it hasn't been created.

Any suggestions?

Thanks.

Try adding @wishlist.save to the end.

Actually, maybe structure it so you are adding a member to the current_user.wishlists collection. If you do that, and you do this in a before_save filter, then the wishlist will be saved along with the user. Read the Rails guides about associations and auto-save. I know there's something in there that covers this.

def set_wishlist   @wishlist = current_user.wishlists.create(params[:wishlist]) end

That one-liner ought to Just Work™.

Walter

That one-liner ought to Just Work.

Walter

I have my code like this but I just doesn't seem to generate a wishlist :frowning:

before_filter :set_wishlist, :only => :create

  def set_wishlist     @wishlist = Wishlist.create(params[:wishlist])     @wishlist.user = current_user     @wishlist.save   end

That one-liner ought to Just Work.

Walter

I have my code like this but I just doesn't seem to generate a wishlist :frowning:

before_filter :set_wishlist, :only => :create

def set_wishlist    @wishlist = Wishlist.create(params[:wishlist])    @wishlist.user = current_user    @wishlist.save end

And just to confirm, you are doing this in the user controller, right? What do your models look like for wishlist and user then? If you have defined the has_many belongs_to relationship, then the one-liner I showed you:

@wishlist = current_user.wishlists.create(params[:wishlist])

should create the relationship and build and save the wishlist.

Walter

And just to confirm, you are doing this in the user controller, right?

Yes this is all happening in the user model

What do your models look like for wishlist and user then? If you have defined the has_many belongs_to relationship, then the one-liner I showed you:

My user model has a: has_one: wishlist My wishlist model: belongs_to: user

@wishlist = current_user.wishlists.create(params[:wishlist])

should create the relationship and build and save the wishlist.

I have put as you said:

before_filter :set_wishlist, :only => :create

  def set_wishlist     current_user.wishlists.create(params[:wishlist])   end

But now I have errors return back stating:

undefined method `wishlists' for nil:NilClass

If I change it to wishlist I get the same error as well as Wishlist. If I state params in the def set_wishlist(params) it returns aargument (0 of 1) error.

And just to confirm, you are doing this in the user controller, right?

Yes this is all happening in the user model

What do your models look like for wishlist and user then? If you have defined the has_many belongs_to relationship, then the one-liner I showed you:

My user model has a: has_one: wishlist My wishlist model: belongs_to: user

@wishlist = current_user.wishlists.create(params[:wishlist])

should create the relationship and build and save the wishlist.

I have put as you said:

before_filter :set_wishlist, :only => :create

def set_wishlist    current_user.wishlists.create(params[:wishlist]) end

But now I have errors return back stating:

undefined method `wishlists' for nil:NilClass

If I change it to wishlist I get the same error as well as Wishlist. If I state params in the def set_wishlist(params) it returns aargument (0 of 1) error.

Okay, then you have another issue. For some reason, current_user isn't in the world when the method is being called, or maybe it's not in scope within that method. Can you put a breakpoint inside the method and see what current_user equals at that point? Are you using Devise or Authologic or similar, and are you sure the user is assigned (logged in) at the moment that this method runs?

I didn't try assigning a variable from outside of the method when I did my little test (quoted earlier), just did a static assignment, and it worked. We need to figure out how to get current_user into scope where you need it, and then you can have the same success.

Walter

I know that the correct user is being signed in because certain elements such as adding a product etc. get created based on who is signed in and therefore associates the id of the product with them so that they get displayed under the profile.

The wishlist should be created when I create the user account but at the moment it doesn't do that, I have to click on a button to create the wishlist but my problem with doing that is that the button can be clicked multiple times which I don't want, I just want the user to be able to create one wishlist so my options are to either have it create on user creation or limit the button to one use per user but that is beyond me.

Okay, one last time, and I tested something similar to your application this time. It's much much simpler than we've been trending.

class User < ActiveRecord::Base   # Include default devise modules. Others available are:   # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable   devise :database_authenticatable, :registerable,          :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model   attr_accessible :name, :email, :password, :password_confirmation, :remember_me   has_one :wishlist   after_create :assign_wishlist      private   def assign_wishlist     self.update_attributes :wishlist => Wishlist.create(:user_id => self.id)   end    end

class Wishlist < ActiveRecord::Base   belongs_to :user   has_many :wishlist_items end

Please give that a try, or at least delete my other helpful suggestions, which didn't seem to work with a has_one relationship.

Walter

And even simpler:

  before_create :assign_wishlist      private   def assign_wishlist     self.wishlist = Wishlist.create   end

1.8.7-p352 :003 > User.create! :name => 'Bill', :email => 'bill@bill.co', :password => 'helpermethod', :password_confirmation => 'helpermethod' => #<User id: 5, name: "Bill", created_at: "2012-02-10 19:51:15", updated_at: "2012-02-10 19:51:15", email: "bill@bill.co", encrypted_password: "$2a$10$rq0MdN9T7ErRj3Iqlt/eNOA8t22BbXM1xGNTz5w6LxhY...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil> 1.8.7-p352 :004 > _.wishlist => #<Wishlist id: 4, created_at: "2012-02-10 19:51:15", updated_at: "2012-02-10 19:51:15", user_id: 5> 1.8.7-p352 :005 >

Walter

  before_create :assign_wishlist

  private   def assign_wishlist     self.wishlist = Wishlist.create   end

I placed the above in the user.rb (Is that correct or should it be wishlist.rb?) and It created the account but after looking at the log there was nothing about creating the wishlist like it said in yours, I am truly stumped about what has gone wrong.

In my example, I only saw the wishlist by asking for it. I was testing in console, and I called User.create! with parameters, and when that saved, I did not see anything about the wishlist being created in the console output.

In the next line I used a trick -- underscore picks up the return value from the previous line in Rails console. So I called _.wishlist to find out if the new User had a wishlist. What do you see when you ask for Wishlist.all in console?

I'll try running it again in rails server and see if the server log indicates the wishlist is being created.

Apparently so:

Started GET "/users/sign_up" for 127.0.0.1 at Fri Feb 10 15:20:48 -0500 2012   Processing by Devise::RegistrationsController#new as HTML Rendered /Users/waltd/.rvm/gems/ruby-1.8.7-p352/gems/devise-1.5.3/app/views/devise/shared/_links.erb (1.4ms) Rendered /Users/waltd/.rvm/gems/ruby-1.8.7-p352/gems/devise-1.5.3/app/views/devise/registrations/new.html.erb within layouts/application (20.1ms) Completed 200 OK in 47ms (Views: 44.8ms | ActiveRecord: 0.0ms)

Started POST "/users" for 127.0.0.1 at Fri Feb 10 15:21:02 -0500 2012   Processing by Devise::RegistrationsController#create as HTML   Parameters: {"commit"=>"Sign up", "authenticity_token"=>"IezLEQXCXqvMaJRaIIURbzNJWp5CU6YPx8/prrrrS9Q=", "utf8"=>"✓", "user"=>{"password_confirmation"=>"[FILTERED]", "password"=>"[FILTERED]", "email"=>"waltd@wdstudio.com"}}   SQL (0.2ms) SELECT 1 FROM "users" WHERE ("users"."email" = 'waltd@wdstudio.com') LIMIT 1   SQL (0.1ms) SELECT name FROM sqlite_master WHERE type = 'table' AND NOT name = 'sqlite_sequence'   AREL (0.4ms) INSERT INTO "wishlists" ("updated_at", "user_id", "created_at") VALUES ('2012-02-10 20:21:02.788524', NULL, '2012-02-10 20:21:02.788524')   AREL (0.2ms) INSERT INTO "users" ("current_sign_in_at", "last_sign_in_at", "last_sign_in_ip", "encrypted_password", "email", "sign_in_count", "current_sign_in_ip", "remember_created_at", "name", "reset_password_sent_at", "reset_password_token", "updated_at", "created_at") VALUES (NULL, NULL, NULL, '$2a$10$v6bk7ld4W5MG4F0H91vpregCN/xF0P.gwyM9tfH4tQ/H8zAMU3i4a', 'waltd@wdstudio.com', 0, NULL, NULL, NULL, NULL, NULL, '2012-02-10 20:21:02.822993', '2012-02-10 20:21:02.822993')   AREL (0.1ms) UPDATE "wishlists" SET "updated_at" = '2012-02-10 20:21:02.825246', "user_id" = 6 WHERE "wishlists"."id" = 5   AREL (0.2ms) UPDATE "users" SET "current_sign_in_at" = '2012-02-10 20:21:02.827881', "last_sign_in_at" = '2012-02-10 20:21:02.827881', "last_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "current_sign_in_ip" = '127.0.0.1', "updated_at" = '2012-02-10 20:21:02.828227' WHERE "users"."id" = 6 Redirected to http://localhost:3000/ Completed 302 Found in 268ms

You're going to have to show me your models if I'm going to be of any further help to you here.

Walter

This is my user model:

class User < ActiveRecord::Base   has_one :profile   has_many :games   has_one :wishlist

  attr_accessor :password   before_save :encrypt_password

  validates_presence_of :username   validates_length_of :username, :within => 6..20, :message => "must contain between 6 to 20 characters"   validates_uniqueness_of :username   validates_presence_of :email   validates_uniqueness_of :email   validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create   validates_confirmation_of :password   validates_length_of :password, :within => 8..20, :message => "must contain between 8 to 20 characters"   validates_presence_of :password, :on => :create   validates_presence_of :password_confirmation

  before_create :assign_wishlist

private   def assign_wishlist     self.wishlist = Wishlist.create   end

    def encrypt_password     if password.present?       self.password_salt = BCrypt::Engine.generate_salt       self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)     end   end

  def self.authenticate(email, password)     user = find_by_email(email)     if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)       user     else       nil     end   end end

and the following is my wishlist model:

class Wishlist < ActiveRecord::Base   belongs_to :user   validates_presence_of :number_1   validates_presence_of :number_2   validates_presence_of :number_3   validates_presence_of :number_4   validates_presence_of :number_5

end