I'm trying to define user created roles that select permissions from a list of permissions. I want a permission like this:
def initialize(user)
user.projects_users.each do |project_user|
project_user.role.privileges do |privilege|
can :create, ProjectsUser, :project_id => project_user.project_id
end
end
end
But I'm trying to save privileges in a database in such a way that I can do this to get the outcome above
def initialize(user)
user.projects_users.each do |project_user|
project_user.role.privileges do |privilege|
can privilege.action.to_sym, privilege.subject_class.constantize, privilege.conditions
end
end
end
The problem lies in the 'privilege.conditions' part. I cannot store a condition that must be executed only in the Ability.rb file. If I try to store:
{ :project_id => project_user.project_id }
It would say there is no variable named 'project_user'. I could save it as a string and in my Ability file do eval(privilege.condition), however I would need to do this only on the values. I tried something like this:
def initialize(user)
user.projects_users.each do |project_user|
project_user.role.privileges do |privilege|
can privilege.action.to_sym, privilege.subject_class.constantize, privilege.conditions.each do |subject, id|
subject => eval(id)
end
end
end
end
The error I'm getting is 'syntax error, unexpected =>, expecting keyword_end' for the 'subject =>' piece.
Not sure how to do this exactly...
I'm using this line of commands to test it:
@user_id = 4
@role = Role.create(name: "Tester", project_id: 4)
@priv = Privilege.create(:action => :create, :subject_class => 'ProjectsUser', :conditions => { :project_id => 'project_user.project_id' })
@role.privileges << @priv
@project_user = ProjectsUser.create(:user_id => @user_id, :role_id => @role.id, :project_id => @role.project_id)
@a = Ability.new(User.find(@user_id))
@a.can?(:create, ProjectsUser.new(:user_id => @user_id + 1, :role_id => @role.id, :project_id => @role.project_id))
Any advice?
Ok So I found a really easy work around. Essentially the do block on the conditions was not being evaluated correctly. Here's the working code:
Notice the
Hash[privilege.conditions.map {|subject, condition| [subject, eval(condition)] }]
What this is doing is taking a symbol as the key in conditions such as :subject_id and mapping it to the evaluated condition, which evaluated to a particular id.
In my model I have
And an example model is:
Update
This method only works for conditions that are one level deep. A condition like this would NOT work. You will get a: TypeError: no implicit conversion of Hash into String
This is not the best solution, but a work around this is