views:

36

answers:

1

Hello, could really use your help, understanding this complex rails issue I've been banging by head against the wall on...

I have the following Models:

Permissions (user_id, role_id, project_id) 
Roles (id, name) 
Projects (id, name)

Permissions is the Y model for Roles and Projects.

I'm struggling to make a form to allow a user to either Add or Update a User's Project permission

In the controller I have:

@project = Space.find(params[:project_id])
@permission = @project.permissions.find_by_user_id(params[:user_id])

And then in the view:

<%=form_for [:space, @permission] do |f| %>....

But this isn't working, errors:

  • If the criteria of (user & project) don't have any records in the DB: "undefined method `model_name' for NilClass:Class"

  • If there is a record in the DB, meaning the user does have a role on this project: "No route matches {:action=>"destroy", :controller=>"permissions", :project_id=>#<Permission project_id: 3, role_id: 2, user_id: 13>}"

Ideally, I want this form to show the current permission if any for the given (Used/Project)... If there isn't a current permission, I want the person to be able to create a record.

Anyone experiences around this type of relationship in Rails 3? Thank you for any tips you can send my way.

Routes file (the part that's specific to these models)

resources :projects do
  resources :photos, :permissions
    collection do
        get 'yourcurrentprojects'
    end
end

Controllers - Path where users are giving the option to CRUD a permission: /projects/3/permissions - I believe I'd want to use Permissions.rb def Show and def Update to get and set permissions?

+2  A: 

For the first error where you have a nil object you should pass in a blank object wherever you're passing objects to forms eg @permission ||= @project.permissions.new (assuming it's the permission object that is causing the nil object. Or to be fancier @project.permissions.find_or_initialize_by_user_id(params[:user_id]).

For the second error, It's odd that it's trying to map to destroy, it should be trying to map to the :update action right? run rake routes to see all routes in the application to verify that the PUT /projects/:project_id/permissions/:id action exists and maps to permissions#update

Jeremy
@Jeremy, thanks for this... I just updated my permissions controller with your suggestion: "@permission = @project.permissions.find_or_initialize_by_user_id(params[:user_id])" No error there, but in the logs, it's not querying the permissions table.
AnApprentice
@Jeremy, my mistake it is... Can you talk to me about the form where it shows the current setting if any and allows the user to modify... Is this the right setup? "<%=form_for [:project, @permission] do |f| %>"
AnApprentice
Regarding Rake Routes, they look good, I'm guessing it's something to do with the form_for tag... "space_permission PUT /projects/:project_id/permissions/:id(.:format) {:controller=>"permissions", :action=>"update"}"
AnApprentice
If I try "<%=form_for(@permission) do |f| %>" i get: "undefined method `permission_path' for #<#<Class:0x10305de18>:0x1030545c0>"
AnApprentice
That would indicate that @permission isn't an instance of a Permission object. Try putting `debugger` just before your `form_for` call, and start your webserver with `rails server --debugger`. Check what's actually stored in the @permission object
Jeremy
Very interesting, I haven't used that before.... Looking through the error now... In the debugger, I'm at line "@user = User.find(params[:user_id])" Looks like it isn't finding the user? "(rdb:2) @usernil(rdb:2) @user.inspect"nil"(rdb:2) params[:user_id]"13"(rdb:2) "
AnApprentice
Strange: "@permission = @project.permissions.find_or_initialize_by_user_id(params[:user_id]) … (rdb:2) @permission ….. RETURNS: nil …. But (rdb:2) @project.permissions.find_or_initialize_by_user_id(params[:user_id]) DOES RETURN: #<Permission project_id: 3, role_id: 2, user_id: 13> Does that make any sense?
AnApprentice
Ok I see, it shows me the line it's about to run... well in that case, it is getting the permission object. ANy thoughts on what the Form_For tag is supposed to look like?
AnApprentice
@Jeremy. For a permission that does not currently exist, the form that renders looks good "<form method="post" id="new_permission" class="new_permission" action="/projects/3/permissions" accept-charset="UTF-8">" it's the existing records that are breaking it.
AnApprentice
I got the form to work by using "<%=form_for [:project, @permission], :url => { :action => "update" } do |f| %>" What's confusing is, for a (Project, Role, User) record that does NOT exist in the DB table, the forms shows a record of it... Is that what the "find_or_initialize_by_user_id" is all about? That's confusing since it shows that role.id = 1, which is ADMIN, which is very untrue if a record does not exist... Is there a clever method that initalizes the user but with a Nil Role, forcing the admin to select the role?
AnApprentice
`find_or_initialize` basically takes the conditions you're searching on (here that it would already belong to @project, and have the given user_id), if no record is found with these, then it essentially returns `@project.permissions.new(:user_id => params[:user_id])` (a new object which is not yet saved to the database). The reason for using this is that if you're passing in this blank object as opposed to nil, the form can detect what object you're wanting to create (because the record doesn't exist, it should automatically route to permissions#create instead of permissions#update).
Jeremy
In the code you've just posted to make it work for #update that may break for permissions that don't exist yet. It's a bit ugly but you could try using `<%=form_for [:project, @permission], :url => { :action => (@permission.new_record? ? "create" : "update") } do |f| %>` (new_record? returns true if @permission is an object which does not yet exist in the database).
Jeremy