cancan with one role per user - any way to set up abilities without repeating so much text?

孤街浪徒 提交于 2019-12-11 02:45:30

问题


My ability model looks something like this:

class Ability
    include CanCan::Ability

    def initialize(user)
        if user.role == "moderator"
            can :manage, [Forum, Post]
        elsif user.role == "admin"
            can :manage, [Enrollment, SiteCare, Forum, Post]
        elsif user.role == "superadmin"
            can :manage, [Permission, Enrollment, SiteCare, Forum, Post]
        end
    end
end

In reality some of the roles have a dozen items they manage. To simplify things how can i construct some ruby that would keep me from having to duplicate so much text? Perhaps something like this construct?

class Ability
    include CanCan::Ability

    def initialize(user)
        a = "Forum, Post"
        b = "Enrollment, SiteCare"
        c = "Permission"

        if user.role == "moderator"
            can :manage, [{a}]
        elsif user.role == "admin"
            can :manage, [{a + b}]
        elsif user.role == "superadmin"
            can :manage, [{a + b + c}]
        end
    end
end

Thanks.

P.S. I am aware of the multiple role per user methods (bitmask and Separate Role Model) and prefer not setting up the additional models or database tables.


回答1:


I use the Separate Role Model myself. Following your code model, I can think of a way. Merge the strings, then for each object (separated by colons) use constantize, so you will get a constant.

class Ability
    include CanCan::Ability

    def initialize(user)
        a = "Forum,Post"
        b = "Enrollment,SiteCare"
        c = "Permission"

        if user.role == "moderator"
            can :manage, permissions(a)
        elsif user.role == "admin"
            can :manage, permissions(a, b)
        elsif user.role == "superadmin"
            can :manage, permissions(a, b, c)
        end
    end

  private
    # TODO: think of a better function name?
    def permissions(*args)
        args.join(",").split(",").map(&:constantize)
    end
end

The join followed by a split is necessary. You join all the strings, and then separate each class (forum, post etc.) into a new string. After that is done, you call constantize on each string, receiving a constant which you can use. "Forum" -> Forum

I did basic tests with irb without the constantize and it seems to be working fine. Try it!



来源:https://stackoverflow.com/questions/7034073/cancan-with-one-role-per-user-any-way-to-set-up-abilities-without-repeating-so

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!