Forum: Ruby on Rails HABTM and radio_button

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Elliott G. (Guest)
on 2009-03-17 00:09
(Received via mailing list)
Hello.

Stuck on some HABTM stuff here... I'm new to rails and I'm kinda lost
on this topic.
FYI This is all within the context of a working restful_authentication
and role_requirement  setup. I am simply adding a radio button pair to
my new user form. When submitted, I need the appropriate tables
updated. As is, only the user table will update. The join table will
not. I have tried a handful of different things both for the
fields_for params and inside the controller's create action with no
luck yet. Here's what I have below.

Thanks for the input!

THE CLASSES:
class User < ActiveRecord::Base
    has_and_belongs_to_many :roles
end

class Role < ActiveRecord::Base
  has_and_belongs_to_many :users
end

THE CONTROLLER: Edited for brevity...
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    logout_keeping_session!
    username = params[:user][:first_name]
    username  += params[:user][:last_name]
    params[:user][:login] = username

    # Create a random password.
    random_p = User.generate_pass 8
    params[:user][:password] = random_p

    @user = User.new(params[:user])

    success = @user && @user.save
    if success && @user.errors.empty?
      redirect_back_or_default('/')
      flash[:notice] = "Thanks for signing up!"
    else
      flash[:error]  = "Too bad sucka!"
      render :action => 'new'
    end
  end
end


THE FORM: new.html.erb
<% form_for @user do |f| -%>

<p><%= label_tag 'first_name' %><br/>
<%= f.text_field :first_name %></p>

<p><%= label_tag 'last_name' %><br/>
<%= f.text_field :last_name %></p>

<p><%= label_tag 'email' %><br/>
<%= f.text_field :email %></p>

<% fields_for :role, @roles do |ff| %>
  <p>Select account type:<br>
  <%= label_tag :name_user, "User" %>
  <%= ff.radio_button :name, "user" %>

  <%= label_tag :name_admin, "Admin" %>
  <%= ff.radio_button :name, "admin" %>
  </p>
<% end %>

<p><%= submit_tag 'Sign up' %></p>
<% end -%>


Here's a sample of how the params are going out:
Processing UsersController#create (for 127.0.0.1 at 2009-03-16
17:59:38) [POST]
  Parameters: {"user"=>{"first_name"=>"Willy", "last_name"=>"Wonka",
"email"=>"removed_email_address@domain.invalid"}, "commit"=>"Sign up",
"authenticity_token"=>"05d982e6eabe5eba6dac466723f9402b9522b3b1",
"role"=>{"name"=>"admin"}}
"Wolas!" (Guest)
on 2009-03-17 11:59
(Received via mailing list)
If i understood correctly, you want the role to be added to the user
upon creation, but its not.

here is the code that would do it

def create
    logout_keeping_session!
    params[:user][:login] = params[:user][:first_name] + params[:user]
[:last_name]

    # Create a random password.
    params[:user][:password] = User.generate_pass 8

    @user = User.new(params[:user], :roles => [ Role.new(params
[:role]) ]    # in an array

    # success = @user && @user.save     # user will always have
something, therefore this line is redundant

    if @user.save
      redirect_back_or_default('/')
      flash[:notice] = "Thanks for signing up!"
    else
      flash[:error]  = "Too bad sucka!"
      render :action => 'new'
    end
  end

hope it helps
Elliott G. (Guest)
on 2009-03-18 02:27
(Received via mailing list)
Wolas!,

Thanks for the reply. I will be able to try this out in the morning.
I'll get back to you with the results.

Elliott
Elliott G. (Guest)
on 2009-03-18 15:21
(Received via mailing list)
When I implement this line:
 @user = User.new(params[:user], :role => [ Role.new(params[:role]) ])

I get this argument error.
  ArgumentError in UsersController#create
  wrong number of arguments (2 for 1)

Any thoughts?

Thanks
(Guest)
on 2009-03-18 15:31
(Received via mailing list)
On 18 Mar., 14:20, elliottg <removed_email_address@domain.invalid> wrote:
> When I implement this line:
>  @user = User.new(params[:user], :role => [ Role.new(params[:role]) ])
>
> I get this argument error.
>   ArgumentError in UsersController#create
>   wrong number of arguments (2 for 1)
>
> Any thoughts?
>
> Thanks

The #new method only accepts one argument. Do this instead:

@user = User.new(params[:user].merge(:role => Role.new(params
[:role])))

--
Cheers,
David K.
http://twitter.com/rubyguy
Elliott G. (Guest)
on 2009-03-18 16:05
(Received via mailing list)
Thanks for the input. That does prevent the error but it does not
actually update the roles_users join table that is a part of the habtm
association between User and Role.

I just tried this code within Create and it seems to work:...
 @user = User.new(params[:user])
 @user.roles.build(params[:role])

However, I have a question still. I was assuming that the Roles table
would not actually have a new record added when saving an habtm assoc.
model. I assumed only the join table and the Users table would be
updated. Otherwise it seems as though I would have a lot of redundant
data in my Roles table. Am I misunderstanding something here?

Thanks heaps
Elliott G. (Guest)
on 2009-03-18 22:24
(Received via mailing list)
Just another question that may help me better understand habtm
workings...

Would it be true that in order to create a fully functional habtm
record that both models using the habtm assoc. need to be updated and
saved? Or is it possible to do having a fully working relationship by
saving only one of the two?

Thanks
(Guest)
on 2009-03-19 09:08
(Received via mailing list)
On 18 Mar., 15:04, elliottg <removed_email_address@domain.invalid> wrote:
> model. I assumed only the join table and the Users table would be
> updated. Otherwise it seems as though I would have a lot of redundant
> data in my Roles table. Am I misunderstanding something here?

I'm not sure how you'ld expect the roles table *not* to be updated. I
mean, you are telling Rails to build a role:

@user.roles.build(params[:role])

If only the users table and the roles_users table were updated the
role would not exist. Remember, the join table only contains two
columns: role_id and user_id. In order to register an HABTM in the
join table there must be *one* role and *one* user. If it still
doesn't make sense to you, I recommend that read the documentation for
HABTM associations:
http://api.rubyonrails.org/classes/ActiveRecord/As...

--
Cheers,
David K.
http://twitter.com/rubyguy
Elliott G. (Guest)
on 2009-03-19 17:42
(Received via mailing list)
Thanks for the input David.

I'll explain myself a bit more here, maybe you could help me further?

I am building an interface so an admin can create new users and assign
them to have either a "user" or "admin" role using
restful_authentication
and role_requiremnt.

I have a roles table that I have manually placed two records under the
Name
column for both "user" and "admin". These are the only two user roles
expected.
It seems that if each time I add a new user and I add a new record
under the Name column
of the roles table as well that I am going to have a lot of redundant
data in roles. IE there could be twenty entries under Name roles that
say "user" and
then X amount more that say "admin". It would seem that I only need
one record
for each in roles to adhere to some semblance of DB normalcy
ideals.?.?.

Should only the user table and the join table be updated to somehow
map to the correct existing roles Name record? IE "user" or "admin".
And if so, whats the code to do that?

Thanks a ton for the help here!
(Guest)
on 2009-03-20 22:22
(Received via mailing list)
On 19 Mar., 16:41, elliottg <removed_email_address@domain.invalid> wrote:
> Name
> ideals.?.?.
>
> Should only the user table and the join table be updated to somehow
> map to the correct existing roles Name record? IE "user" or "admin".
> And if so, whats the code to do that?

If you would like to associate multiple users with the same two roles
in your database, you would have to do it like this:

@user.roles << Role.find_by_name(params[:role_name])

Keep in mind, that this is going to allow the user to have multiple
roles. The #<< method is going to add another role to the collection
of roles, the user already has. The params[:role_name] is simply the
name of the role, you'ld like the user to have, for example "admin".

--
Cheers,
David K.
http://twitter.com/rubyguy
This topic is locked and can not be replied to.