From 6144d62a52512bf4aa004ba338c01aa492fab4ce Mon Sep 17 00:00:00 2001 From: Nicolae Claudius Date: Thu, 26 Jan 2012 10:48:10 -0800 Subject: [PATCH] permissions finished --- Gemfile.lock | 8 +++---- config/initializers/cancan.rb | 41 ++++++++++++++++++-------------- config/initializers/squeel.rb | 3 +-- spec/models/domain_spec.rb | 13 +++++++---- spec/models/record_spec.rb | 44 +++++++++++++++++++---------------- 5 files changed, 61 insertions(+), 48 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7fbf887..9bad066 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,7 +100,7 @@ GEM guard-spork (0.3.2) guard (>= 0.8.4) spork (>= 0.8.4) - highline (1.6.9) + highline (1.6.11) hike (1.2.1) i18n (0.6.0) jquery-rails (1.0.19) @@ -199,12 +199,12 @@ GEM multi_json (~> 1.0.3) simplecov-html (~> 0.5.3) simplecov-html (0.5.3) - spork (0.9.0.rc9) + spork (0.9.0) sprockets (2.0.3) hike (~> 1.2) rack (~> 1.0) - tilt (!= 1.3.0, ~> 1.1) - squeel (0.9.3) + tilt (~> 1.1, != 1.3.0) + squeel (0.9.5) activerecord (~> 3.0) activesupport (~> 3.0) polyamorous (~> 0.5.0) diff --git a/config/initializers/cancan.rb b/config/initializers/cancan.rb index aa58c67..877526b 100644 --- a/config/initializers/cancan.rb +++ b/config/initializers/cancan.rb @@ -1,4 +1,19 @@ # https://gist.github.com/1523940 + +class String + include Squeel::Nodes::PredicateOperators +end + +module Squeel + module Visitors + class PredicateVisitor < Visitor + def visit_String(o, parent) + Arel::Nodes::SqlLiteral.new(o) + end + end + end +end + module CanCan module ModelAdapters @@ -35,24 +50,14 @@ module CanCan else raise NotImplemented, "The #{method} Squeel condition is not supported." end end - - def tableized_conditions(conditions, model_class = @model_class) - return conditions unless conditions.kind_of? Hash - conditions.inject({}) do |result_hash, (name, value)| - name_sym = case name - when Symbol then name - when Squeel::Nodes::Join then name._name - when Squeel::Nodes::Predicate then name.expr - else raise name - end - if value.kind_of? Hash - reflection = model_class.reflect_on_association(name_sym) - association_class = reflection.class_name.constantize - name_sym = reflection.table_name.to_sym - value = tableized_conditions(value, association_class) - end - result_hash[name_sym] = value - result_hash + + # mostly let Squeel do the job in building the query + def conditions + if @rules.size == 1 && @rules.first.base_behavior + # Return the conditions directly if there's just one definition + @rules.first.conditions.dup + else + @rules.reverse.inject(false_sql) {|acc, rule| acc | rule.conditions.dup} end end diff --git a/config/initializers/squeel.rb b/config/initializers/squeel.rb index 47b926e..434aeac 100644 --- a/config/initializers/squeel.rb +++ b/config/initializers/squeel.rb @@ -1,12 +1,11 @@ Squeel.configure do |config| # To load hash extensions (to allow for AND (&), OR (|), and NOT (-) against # hashes of conditions) - config.load_core_extensions :hash # To load symbol extensions (for a subset of the old MetaWhere functionality, # via ARel predicate methods on Symbols: :name.matches, etc) # config.load_core_extensions :symbol - # To load both hash and symbol extensions + # Load both hash and symbol extensions config.load_core_extensions :hash, :symbol end diff --git a/spec/models/domain_spec.rb b/spec/models/domain_spec.rb index 05695ea..688b2e4 100644 --- a/spec/models/domain_spec.rb +++ b/spec/models/domain_spec.rb @@ -69,10 +69,15 @@ describe Domain do it "queries domains corectly in index" do permission3 query = Domain.accessible_by(user.ability(:reload => true)) - wheres = query.where_values - joins = query.joins_values.map{|j| [j._name, j._type]} - wheres.should == ["(`domains`.`name_reversed` = '#{domain3.name_reversed}.%') OR ((`permissions`.`user_id` = #{user.id}) OR (`domains`.`user_id` = #{user.id}))"] - joins.should == [[:permissions, Arel::Nodes::OuterJoin]] + expected = <<-SQL + SELECT `domains`.* FROM `domains` + LEFT OUTER JOIN `permissions` ON `permissions`.`domain_id` = `domains`.`id` + WHERE ((((1=0 OR + `domains`.`user_id` = #{user.id}) OR + `permissions`.`user_id` = #{user.id}) OR + `domains`.`name_reversed` LIKE '#{permission3.domain.name_reversed}.%')) + SQL + query.to_sql.should == expected.gsub("\n", '').gsub(/\s+/, ' ').strip end it "has reversed name" do diff --git a/spec/models/record_spec.rb b/spec/models/record_spec.rb index 25baa11..d91f186 100644 --- a/spec/models/record_spec.rb +++ b/spec/models/record_spec.rb @@ -17,31 +17,35 @@ describe Record do a_record.should be_valid end - def record_joins_expectations(joins) - # joins == [{:domain => Squeel(:permissions, outer)}] - joins.size.should == 1 - joins.first.should be_an_instance_of(Hash) - domain_joins = joins.first[:domain] - domain_joins.size.should == 1 - domain_joins.first[:domain]._name.should == :permissions - domain_joins.first[:domain]._type.should == Arel::Nodes::OuterJoin - end - it "queries records corectly in index" do - wheres = Record.accessible_by(user.ability).where_values - joins = Record.accessible_by(user.ability).joins_values - wheres.should == ["(`permissions`.`user_id` = #{user.id}) OR (`domains`.`user_id` = #{user.id})"] - record_joins_expectations(joins) + permission3 + query = Record.accessible_by(user.ability) + expected = <<-SQL + SELECT `records`.* FROM `records` + INNER JOIN `domains` ON `domains`.`id` = `records`.`domain_id` + LEFT OUTER JOIN `permissions` ON `permissions`.`domain_id` = `domains`.`id` + WHERE ((((1=0 OR + `domains`.`user_id` = #{user.id}) OR + `permissions`.`user_id` = #{user.id}) OR + `domains`.`name_reversed` LIKE '#{permission3.domain.name_reversed}.%')) + SQL + query.to_sql.should == expected.gsub("\n", '').gsub(/\s+/, ' ').strip end - it "queries A records corectly in index" do + it "queries A records corectly in index", :focus => true do permission3 query = A.accessible_by(user.ability(:reload => true)) - wheres = query.where_values - joins = query.joins_values - wheres.size.should == 2 - wheres.second.should == "(`domains`.`name_reversed` = '#{domain3.name_reversed}.%') OR ((`permissions`.`user_id` = #{user.id}) OR ((`records`.`user_id` = #{user.id}) OR (`domains`.`user_id` = #{user.id})))" - record_joins_expectations(joins) + expected = <<-SQL + SELECT `records`.* FROM `records` + INNER JOIN `domains` ON `domains`.`id` = `records`.`domain_id` + LEFT OUTER JOIN `permissions` ON `permissions`.`domain_id` = `domains`.`id` + WHERE `records`.`type` IN ('A') AND (((((1=0 OR + `domains`.`user_id` = #{user.id}) OR + `records`.`user_id` = #{user.id}) OR + `permissions`.`user_id` = #{user.id}) OR + `domains`.`name_reversed` LIKE '#{permission3.domain.name_reversed}.%')) + SQL + query.to_sql.should == expected.gsub("\n", '').gsub(/\s+/, ' ').strip end end