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