Reputation: 43
I am a beginner in rails and have been trawling through many suggested answers to this problem. I can't seem to translate the answers, I've seen to my situation. I'm hoping someone would be kind enough to shed some light on it. The 2 models, I am concerned with are User and Project. Each User can create a project, but each user can also manage a project. To allow for this, I have created a has_many :through relationship between User and Project, using a managing model to connect the two models.
user.rb
has_many :managings, foreign_key: "manager_id", dependent: :destroy
has_many :managed_projects, through: :managings
managing.rb
belongs_to :manager, class_name: "User"
belongs_to :managed_project, class_name: "Project"
project.rb
has_one :reverse_managing, foreign_key: "managed_project_id",
class_name: "Managing",
dependent: :destroy
has_one :manager, through: :reverse_managing, source: :manager
So, I have a role called 'Beginner'. Beginners can only read projects, with the exception of those who choose to be managers of a project. Managers should also be allowed to edit and update a project, which they are managing.
Below is my attempt at this in ability.rb
user ||= User.new # guest user (not logged in)
if user.role? :Admin
can :manage, :all
elsif user.role? :Author
can :read, :all
can [:create], [Project]
can [:edit, :update], Project, :user_id => user.id
elsif user.role? :Beginner
can :read, :all
can [:edit, :update], Project, :manager_id => user.id
end
The last line doesn't appear to be working, as I am not seeing an edit link when I look at the project view of a beginner who is managing that project.
Here is the code that I use in the view:
<% if can? :update, project %>
<%= link_to 'Edit', edit_project_path(project) %>
<% end %>
and this is what appears in projects_controller
def edit
@project = Project.find(params[:id])
authorize! :edit, @project
end
I will sleep a happy man if someone can help me on this
UPDATE
here is the role? method in User.rb
def role?(role)
return !!self.roles.find_by_name(role.to_s.camelize)
end
UPDATE
I had the wrong role_id assigned to the user. After correcting this, I got an error message, when I tried to open the project view containing the edit link.
undefined method `manager_id' for #<Project:0xb387f0b0>
Upvotes: 3
Views: 3499
Reputation: 1008
The problem is here:
can [:edit, :update], Project, :manager_id => user.id
cancan ability conditions must only use database columns (as per the cancan wiki). Here cancan expects manager_id to be a column in the Project model, which is actually is not the case. Your models look somewhat like this:
User [id, ...]
Project [id, ...]
Managings [manager_id, managed_project_id, ...]
manager_id is a field in Managings, and not in Project.
The fix is to use block conditions as described in another wiki page. I've not tested it, but I think the following will work -
can [:edit, :update], Project do |p|
p.manager == user
end
Upvotes: 8