views:

48

answers:

2

I constructed a Many-to-Many association between Users and Roles.

When a non-administrator logs in, I have hidden the Edit Role function, using

using the following code:

view/users/edit.html.erb

<%= error_messages_for :user %>

<% form_for @user do |f| -%>
  <p><label for="login">Login</label><br/>
  <%= f.text_field :login %></p>

  <p><label for="email">Email</label><br/>
  <%= f.text_field :email %></p>

  <p><label for="password">Password</label><br/>
  <%= f.password_field :password %></p>

  <p><label for="password_confirmation">Confirm Password</label><br/>
  <%= f.password_field :password_confirmation %></p>

  <% if admin? %>
  <% for role in Role.find(:all) %>
 <div>
  <%= check_box_tag "user[role_ids][]", role.id, @user.roles.include?(role) %>
  <%= role.name %>
 </div>
 <% end %>
 <% else %>
 <% hidden_field :email, :email %>
 <% end %>

  <p><%= submit_tag 'Update' %></p>
<% end %>

the terminal output, was what I expected and is as follows:

Processing UsersController#update (for 127.0.0.1 at 2010-01-05 21:28:54) [PUT]
  Parameters: {"commit"=>"Update", "action"=>"update", "_method"=>"put", "authenticity_token"=>"E6qUNM3gS9OmxuAZpmF7FE2Mr/lowznNLMd6ENNT6uk=", "id"=>"5", "controller"=>"users", "user"=>{"password_confirmation"=>"[FILTERED]", "password"=>"[FILTERED]", "login"=>"lesa", "email"=>"[email protected]"}}

However when I was surprised the user lost her rights (prior to her password update her roles: [1,2])

>> user = User.find_by_login("lesa")
=> #<User id: 5, login: "lesa", email: "[email protected]", crypted_password: "58026ae120d0686196df3c72c9e3df5da596326d", salt: "f02ef9e00d16f1b9f82dfcc488fdf96bf5aab4a8", created_at: "2009-12-29 15:15:51", updated_at: "2010-01-05 21:28:54", remember_token: nil, remember_token_expires_at: nil>
>> user.role_ids
=> []
>> 

In the user model controller I am using:

attr_accessible :login, :email, :password, :password_confirmation, :role_ids

How would it be possible for users without the proper rights (role) to NOT update their role_ids? Obviously what I have is seriously flawed. Below is the terminal output of an Administrator correcting Lesa's Rights (role).

Processing UsersController#update (for 127.0.0.1 at 2010-01-05 21:34:01) [PUT]
  Parameters: {"commit"=>"Update", "action"=>"update", "_method"=>"put", "authenticity_token"=>"/yC1s9T8yWZH+eM5fnhPwdeHPCTcT1d8IGoIn+tEd4Q=", "id"=>"5", "controller"=>"users", "user"=>{"password_confirmation"=>"[FILTERED]", "role_ids"=>["2"], "password"=>"[FILTERED]", "login"=>"lesa", "email"=>"[email protected]"}}

User controller code:

class UsersController < ApplicationController
  # Be sure to include AuthenticationSystem in Application Controller instead

    #routine that is excecuted before every action in controller "Before_filter
  before_filter :login_required
  require_role "admin", :for => [:index, :create, :destroy]

  def index
    @users = User.find(:all)
  end

 def show
  @user = User.find(params[:id])
 end

 def destroy
  @user = User.find(params[:id])
  @user.destroy

  redirect_to(users_url)
 end

 def edit
    @user = User.find(params[:id])
 end

 def update
    @user = User.find(params[:id])

  params[:user][:role_ids] ||= []

  if @user.update_attributes(params[:user])
     flash[:notice] = 'User was successfully updated.'
    redirect_to(user_path(@user))
 else
    render :action => 'edit'
 end
 end

  # render new.rhtml
  def new
  end

  def create
    cookies.delete :auth_token
    # protects against session fixation attacks, wreaks havoc with 
    # request forgery protection.
    # uncomment at your own risk
    # reset_session
    @user = User.new(params[:user])
    @user.save
    if @user.errors.empty?
      self.current_user = @user
      redirect_back_or_default('/')
      flash[:notice] = "Thanks for signing up!"
    else
      render :action => 'new'
    end
  end

end
A: 

are there any callbacks in the model? are you sure the roles existed before you updated? have you tried using accepts_nested_attributes_for :roles in the User model? I'd have loved to see your controller code too.

Updated Your User#update action sets this to an empty array if nothing comes.... not ideal dude, as only admins will update them, and all other update requests get set as, well, nothing as you found out. scrap it. Use accepts_nested_attributes_for the roles and somehow lock out who can update them...

pjammer
Yeah definitely existed before the update. I added the controller code above. and I haven't tried accepts_nested_attributes_for :roles yet.
JZ
just read up on accepts_nested_attributes_for and I don't think that is what I need. My code updates the Role, it just fails to function when I don't want it to update the Role.
JZ
did you read my updated part yet? if it works i think you got your answer.
pjammer
A: 

Of course!

I Eliminated this code from my controller: params[:user][:role_ids] ||= [] to solve this issue.

JZ