From af5271eb4ee71f4b5e9fafe42898c84aeec21c6c Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Tue, 16 Jan 2024 23:02:12 +0200 Subject: [PATCH] Unconditional relation on ActiveModel::AttributesAssignment --- lib/datagrid/core.rb | 28 ++----- spec/datagrid/columns_spec.rb | 78 +++++++++---------- spec/datagrid/filters/date_filter_spec.rb | 92 +++++++++++------------ 3 files changed, 93 insertions(+), 105 deletions(-) diff --git a/lib/datagrid/core.rb b/lib/datagrid/core.rb index 855944be..4eb1cc0f 100644 --- a/lib/datagrid/core.rb +++ b/lib/datagrid/core.rb @@ -16,9 +16,7 @@ def self.included(base) class_attribute :dynamic_block, instance_writer: false class_attribute :forbidden_attributes_protection, instance_writer: false self.forbidden_attributes_protection = false - if defined?(::ActiveModel::AttributeAssignment) - include ::ActiveModel::AttributeAssignment - end + include ::ActiveModel::AttributeAssignment end base.include InstanceMethods end @@ -155,7 +153,7 @@ def attributes # @return [Object] Any datagrid attribute value def [](attribute) - self.send(attribute) + self.public_send(attribute) end # Assigns any datagrid attribute @@ -163,7 +161,7 @@ def [](attribute) # @param value [Object] Datagrid attribute value # @return [void] def []=(attribute, value) - self.send(:"#{attribute}=", value) + self.public_send(:"#{attribute}=", value) end # @return [Object] a scope relation (e.g ActiveRecord::Relation) with all applied filters @@ -171,21 +169,6 @@ def assets scope end - # Updates datagrid attributes with a passed hash argument - def attributes=(attributes) - if respond_to?(:assign_attributes) - if !forbidden_attributes_protection && attributes.respond_to?(:permit!) - attributes.permit! - end - assign_attributes(attributes) - else - attributes.each do |name, value| - self[name] = value - end - self - end - end - # Returns serializable query arguments skipping all nil values # @example # grid = ProductsGrid.new(category: 'dresses', available: true) @@ -273,6 +256,11 @@ def ==(other) attributes == other.attributes && scope == other.scope end + + protected + def sanitize_for_mass_assignment(attributes) + forbidden_attributes_protection ? super(attributes) : attributes + end end end end diff --git a/spec/datagrid/columns_spec.rb b/spec/datagrid/columns_spec.rb index edf8b262..9af653d2 100644 --- a/spec/datagrid/columns_spec.rb +++ b/spec/datagrid/columns_spec.rb @@ -2,7 +2,7 @@ describe Datagrid::Columns do - let(:group) { Group.create!(:name => "Pop") } + let(:group) { Group.create!(name: "Pop") } subject do SimpleReport.new @@ -47,7 +47,7 @@ grid = test_report do scope {Entry} column(:name) - column(:action, :html => true) do + column(:action, html: true) do 'dummy' end end @@ -99,21 +99,21 @@ class Report27 report = test_report do scope {Entry} column(:id) - column(:name, :html => false) + column(:name, html: false) end expect(report.html_columns.map(&:name)).to eq([:id]) end it "should return html_columns when column definition has 2 arguments" do - report = test_report(:name => "Hello") do + report = test_report(name: "Hello") do scope {Entry} filter(:name) column(:id) - column(:name, :html => false) do |model, grid| + column(:name, html: false) do |model, grid| "'#{model.name}' filtered by '#{grid.name}'" end end - entry = Entry.create!(:name => "Hello World") + entry = Entry.create!(name: "Hello World") expect(report.row_for(entry)).to eq([entry.id, "'Hello World' filtered by 'Hello'"]) end @@ -135,11 +135,11 @@ class Report27 it "should generate hash for given asset" do expect(subject.hash_for(entry)).to eq({ - :group => "Pop", - :name => "Star", - :access_level => 'admin', - :pet => 'ROTTWEILER', - :shipping_date => date + group: "Pop", + name: "Star", + access_level: 'admin', + pet: 'ROTTWEILER', + shipping_date: date }) end @@ -152,13 +152,13 @@ class Report27 end it "should support csv export options" do - expect(subject.to_csv(:col_sep => ";")).to eq("Shipping date;Group;Name;Access level;Pet\n#{date};Pop;Star;admin;ROTTWEILER\n") + expect(subject.to_csv(col_sep: ";")).to eq("Shipping date;Group;Name;Access level;Pet\n#{date};Pop;Star;admin;ROTTWEILER\n") end end it "should support columns with model and report arguments" do - report = test_report(:category => "foo") do + report = test_report(category: "foo") do scope {Entry.order(:category)} filter(:category) do |value| where("category LIKE '%#{value}%'") @@ -168,8 +168,8 @@ class Report27 entry.category == grid.category end end - Entry.create!(:category => "foo") - Entry.create!(:category => "foobar") + Entry.create!(category: "foo") + Entry.create!(category: "foobar") expect(report.rows.first.first).to eq(true) expect(report.rows.last.first).to eq(false) end @@ -196,7 +196,7 @@ class Report27 column(:id) column(:sum_group_id, 'sum(group_id)') end - Entry.create!(:group => group) + Entry.create!(group: group) expect(report.assets.first.sum_group_id).to eq(group.id) end @@ -216,8 +216,8 @@ class Report27 it "should support hidding columns through if and unless" do report = test_report do scope {Entry} - column(:id, :if => :show?) - column(:name, :unless => proc {|grid| !grid.show? }) + column(:id, if: :show?) + column(:name, unless: proc {|grid| !grid.show? }) column(:category) def show? @@ -241,14 +241,14 @@ def show? expect do test_report do column(:id) - column(:name, :before => :id, :after => :name) + column(:name, before: :id, after: :name) end end.to raise_error(Datagrid::ConfigurationError) end describe ".column_names attributes" do let(:grid) do - test_report(:column_names => ["id", "name"]) do + test_report(column_names: ["id", "name"]) do scope { Entry } column(:id) column(:name) @@ -256,7 +256,7 @@ def show? end end let!(:entry) do - Entry.create!(:name => 'hello') + Entry.create!(name: 'hello') end it "should be suppored in header" do expect(grid.header).to eq(["Id", "Name"]) @@ -286,7 +286,7 @@ def show? end end end - Entry.create!(:name => "Hello World") + Entry.create!(name: "Hello World") expect(report.rows).to eq([["Hello World"]]) end end @@ -295,17 +295,17 @@ def show? it "should pass default options to each column definition" do report = test_report do scope {Entry} - self.default_column_options = {:order => false} + self.default_column_options = {order: false} column(:id) - column(:name, :order => "name") + column(:name, order: "name") end - first = Entry.create(:name => '1st') - second = Entry.create(:name => '2nd') + first = Entry.create(name: '1st') + second = Entry.create(name: '2nd') expect do - report.attributes = {:order => :id} + report.attributes = {order: :id} report.assets end.to raise_error(Datagrid::OrderUnsupported) - report.attributes = {:order => :name, :descending => true} + report.attributes = {order: :name, descending: true} expect(report.assets).to eq([second, first]) end end @@ -380,8 +380,8 @@ def show? describe "column value" do it "should support conversion" do group = Group.create! - Entry.create(:group => group) - Entry.create(:group => group) + Entry.create(group: group) + Entry.create(group: group) grid = test_report do scope { Group } column(:entries_count) do |g| @@ -407,7 +407,7 @@ def show? end let(:basic_grid) { modified_grid.class.new } - let!(:entry) { Entry.create!(:name => "Hello", :category => 'first') } + let!(:entry) { Entry.create!(name: "Hello", category: 'first') } it "should have correct columns" do expect(modified_grid.columns.size).to eq(2) @@ -426,12 +426,12 @@ def show? end it "should support :before column name" do - modified_grid.column(:category, :before => :name) + modified_grid.column(:category, before: :name) expect(modified_grid.header).to eq(["Id", "Category", "Name"]) end it "should support :before all" do - modified_grid.column(:category, :before => true) + modified_grid.column(:category, before: true) expect(modified_grid.header).to eq(["Category", "Id", "Name"]) end @@ -449,7 +449,7 @@ def show? expect(modified_grid.rows).to eq([[entry.id]]) end it "should support column_names accessor with mandatory columns" do - modified_grid.column(:category, :mandatory => true) + modified_grid.column(:category, mandatory: true) modified_grid.column_names = [:name] expect(modified_grid.rows).to eq([['Hello', 'first']]) basic_grid.column_names = [:id] @@ -457,12 +457,12 @@ def show? end it "should support available columns" do - modified_grid.column(:category, :mandatory => true) + modified_grid.column(:category, mandatory: true) expect(modified_grid.available_columns.map(&:name)).to eq([:id, :name, :category]) end it "should respect column availability criteria" do - modified_grid.column(:category, :if => proc { false }) + modified_grid.column(:category, if: proc { false }) expect(modified_grid.columns.map(&:name)).to eq([:id, :name]) end end @@ -473,15 +473,15 @@ def show? scope {Entry } column(:name) end - expect(grid.data_value(:name, Entry.create!(:name => 'Hello'))).to eq('Hello') + expect(grid.data_value(:name, Entry.create!(name: 'Hello'))).to eq('Hello') end it "should raise for disabled columns" do grid = test_report do scope {Entry } - column(:name, :if => proc { false }) + column(:name, if: proc { false }) end expect { - grid.data_value(:name, Entry.create!(:name => 'Hello')) + grid.data_value(:name, Entry.create!(name: 'Hello')) }.to raise_error(Datagrid::ColumnUnavailableError) end end diff --git a/spec/datagrid/filters/date_filter_spec.rb b/spec/datagrid/filters/date_filter_spec.rb index 3e396ed2..0f811b73 100644 --- a/spec/datagrid/filters/date_filter_spec.rb +++ b/spec/datagrid/filters/date_filter_spec.rb @@ -4,10 +4,10 @@ describe Datagrid::Filters::DateFilter do it "should support date range argument" do - e1 = Entry.create!(:created_at => 7.days.ago) - e2 = Entry.create!(:created_at => 4.days.ago) - e3 = Entry.create!(:created_at => 1.day.ago) - report = test_report(:created_at => 5.day.ago..3.days.ago) do + e1 = Entry.create!(created_at: 7.days.ago) + e2 = Entry.create!(created_at: 4.days.ago) + e3 = Entry.create!(created_at: 1.day.ago) + report = test_report(created_at: 5.day.ago..3.days.ago) do scope { Entry } filter(:created_at, :date) end @@ -16,19 +16,19 @@ expect(report.assets).not_to include(e3) end - {:active_record => Entry, :mongoid => MongoidEntry, :sequel => SequelEntry}.each do |orm, klass| + {active_record: Entry, mongoid: MongoidEntry, sequel: SequelEntry}.each do |orm, klass| describe "with orm #{orm}", orm => true do describe "date to timestamp conversion" do let(:klass) { klass } subject do - test_report(:created_at => _created_at) do + test_report(created_at: _created_at) do scope { klass } - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end.assets.to_a end def entry_dated(date) - klass.create(:created_at => date) + klass.create(created_at: date) end context "when single date paramter given" do @@ -54,12 +54,12 @@ def entry_dated(date) end it "should support date range given as array argument" do - e1 = Entry.create!(:created_at => 7.days.ago) - e2 = Entry.create!(:created_at => 4.days.ago) - e3 = Entry.create!(:created_at => 1.day.ago) - report = test_report(:created_at => [5.day.ago.to_date.to_s, 3.days.ago.to_date.to_s]) do + e1 = Entry.create!(created_at: 7.days.ago) + e2 = Entry.create!(created_at: 4.days.ago) + e3 = Entry.create!(created_at: 1.day.ago) + report = test_report(created_at: [5.day.ago.to_date.to_s, 3.days.ago.to_date.to_s]) do scope { Entry } - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end expect(report.assets).not_to include(e1) expect(report.assets).to include(e2) @@ -67,12 +67,12 @@ def entry_dated(date) end it "should support minimum date argument" do - e1 = Entry.create!(:created_at => 7.days.ago) - e2 = Entry.create!(:created_at => 4.days.ago) - e3 = Entry.create!(:created_at => 1.day.ago) - report = test_report(:created_at => [5.day.ago.to_date.to_s, nil]) do + e1 = Entry.create!(created_at: 7.days.ago) + e2 = Entry.create!(created_at: 4.days.ago) + e3 = Entry.create!(created_at: 1.day.ago) + report = test_report(created_at: [5.day.ago.to_date.to_s, nil]) do scope { Entry } - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end expect(report.assets).not_to include(e1) expect(report.assets).to include(e2) @@ -80,12 +80,12 @@ def entry_dated(date) end it "should support maximum date argument" do - e1 = Entry.create!(:created_at => 7.days.ago) - e2 = Entry.create!(:created_at => 4.days.ago) - e3 = Entry.create!(:created_at => 1.day.ago) - report = test_report(:created_at => [nil, 3.days.ago.to_date.to_s]) do + e1 = Entry.create!(created_at: 7.days.ago) + e2 = Entry.create!(created_at: 4.days.ago) + e3 = Entry.create!(created_at: 1.day.ago) + report = test_report(created_at: [nil, 3.days.ago.to_date.to_s]) do scope { Entry } - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end expect(report.assets).to include(e1) expect(report.assets).to include(e2) @@ -94,12 +94,12 @@ def entry_dated(date) it "should find something in one day interval" do - e1 = Entry.create!(:created_at => 7.days.ago) - e2 = Entry.create!(:created_at => 4.days.ago) - e3 = Entry.create!(:created_at => 1.day.ago) - report = test_report(:created_at => (4.days.ago.to_date..4.days.ago.to_date)) do + e1 = Entry.create!(created_at: 7.days.ago) + e2 = Entry.create!(created_at: 4.days.ago) + e3 = Entry.create!(created_at: 1.day.ago) + report = test_report(created_at: (4.days.ago.to_date..4.days.ago.to_date)) do scope { Entry } - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end expect(report.assets).not_to include(e1) expect(report.assets).to include(e2) @@ -108,12 +108,12 @@ def entry_dated(date) it "should invert invalid range" do range = 1.days.ago..7.days.ago - e1 = Entry.create!(:created_at => 7.days.ago) - e2 = Entry.create!(:created_at => 4.days.ago) - e3 = Entry.create!(:created_at => 1.day.ago) - report = test_report(:created_at => range) do + e1 = Entry.create!(created_at: 7.days.ago) + e2 = Entry.create!(created_at: 4.days.ago) + e3 = Entry.create!(created_at: 1.day.ago) + report = test_report(created_at: range) do scope { Entry } - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end expect(report.created_at).to eq([range.last.to_date, range.first.to_date]) expect(report.assets).to include(e1) @@ -125,14 +125,14 @@ def entry_dated(date) it "should support block" do date = Date.new(2018, 01, 07) time = Time.utc(2018, 01, 07, 2, 2) - report = test_report(:created_at => date) do + report = test_report(created_at: date) do scope { Entry } - filter(:created_at, :date, :range => true) do |value| + filter(:created_at, :date, range: true) do |value| where("created_at >= ?", value) end end - expect(report.assets).not_to include(Entry.create!(:created_at => time - 1.day)) - expect(report.assets).to include(Entry.create!(:created_at => time)) + expect(report.assets).not_to include(Entry.create!(created_at: time - 1.day)) + expect(report.assets).to include(Entry.create!(created_at: time)) end @@ -144,7 +144,7 @@ def entry_dated(date) end it "should have configurable date format" do - report = test_report(:created_at => "10/01/2013") do + report = test_report(created_at: "10/01/2013") do scope {Entry} filter(:created_at, :date) end @@ -152,7 +152,7 @@ def entry_dated(date) end it "should support default explicit date" do - report = test_report(:created_at => Date.parse("2013-10-01")) do + report = test_report(created_at: Date.parse("2013-10-01")) do scope {Entry} filter(:created_at, :date) end @@ -162,24 +162,24 @@ def entry_dated(date) it "should automatically reverse Array if first more than last" do - report = test_report(:created_at => ["2013-01-01", "2012-01-01"]) do + report = test_report(created_at: ["2013-01-01", "2012-01-01"]) do scope {Entry} - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end expect(report.created_at).to eq([Date.new(2012, 01, 01), Date.new(2013, 01, 01)]) end it "should automatically reverse Array if first more than last" do - report = test_report(:created_at => ["2013-01-01", "2012-01-01"]) do + report = test_report(created_at: ["2013-01-01", "2012-01-01"]) do scope {Entry} - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end expect(report.created_at).to eq([Date.new(2012, 01, 01), Date.new(2013, 01, 01)]) end it "should nullify blank range" do - report = test_report(:created_at => [nil, nil]) do + report = test_report(created_at: [nil, nil]) do scope {Entry} - filter(:created_at, :date, :range => true) + filter(:created_at, :date, range: true) end expect(report.created_at).to eq(nil) @@ -187,7 +187,7 @@ def entry_dated(date) it "should properly format date in filter_value_as_string" do with_date_format do - report = test_report(:created_at => "2012-01-02") do + report = test_report(created_at: "2012-01-02") do scope {Entry} filter(:created_at, :date) end