I just got finished watching a railscast episode #189 and the was using a bit_mask to store a value in the users table. I am trying to implement the same thing but when I test via irb I am getting errors. First can someone explain what this is actually going. I know what the first line is doing and part of the second line
ROLES = %w[admin moderator author]
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.开发者_开发百科index(r) }.sum
end
def roles
ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
end
In irb I get this:
irb(main):013:0> ROLES = %w[admin moderator author]
(irb):13: warning: already initialized constant ROLES
=> ["admin", "moderator", "author"]
irb(main):014:0> roles = %w[admin author]
=> ["admin", "author"]
irb(main):015:0> roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
NoMethodError: undefined method `sum' for [1, 4]:Array
The reason that it doesn't work in irb is that sum
is defined in ActiveSupport, not ruby's standard library. If you require 'active_support'
first (or just use script/console), it will work in irb.
What roles=
does is it turns an array of roles into a bitmask according to the order of roles in the ROLES
array (item) and then saves that bitmask as role_mask
. For example ["admin", "author"]
will be turned into 5 (which is 0b101
in binary). Roles that aren't in ROLES
will be ignored (e.g. ["admin", "bla"]
is the same as just ["admin"]
).
What roles
does is it turns the saved bitmask back into an array of roles.
He's using a number as a bit field. In binary, each bit of the number represents a flag. By adding 2^n, you can set bit n, by subtracting 2^n you can clear it (assuming it was set in the first place).
The Array#sum method might be specific to Rails, or part of Ruby 1.9. All it does is take every element in the array and add them up. You can do it this way instead.
roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0){|m,n| m + n}
精彩评论