Skip to content

Commit

Permalink
Unconditional relation on ActiveModel::AttributesAssignment
Browse files Browse the repository at this point in the history
  • Loading branch information
bogdan committed Jan 16, 2024
1 parent 2c7a2b0 commit af5271e
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 105 deletions.
28 changes: 8 additions & 20 deletions lib/datagrid/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -155,37 +153,22 @@ def attributes

# @return [Object] Any datagrid attribute value
def [](attribute)
self.send(attribute)
self.public_send(attribute)
end

# Assigns any datagrid attribute
# @param attribute [Symbol, String] Datagrid attribute name
# @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
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)
Expand Down Expand Up @@ -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
78 changes: 39 additions & 39 deletions spec/datagrid/columns_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe Datagrid::Columns do

let(:group) { Group.create!(:name => "Pop") }
let(:group) { Group.create!(name: "Pop") }

subject do
SimpleReport.new
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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

Expand All @@ -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}%'")
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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?
Expand All @@ -241,22 +241,22 @@ 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)
column(:category)
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"])
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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|
Expand All @@ -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)
Expand All @@ -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

Expand All @@ -449,20 +449,20 @@ 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]
expect(basic_grid.rows).to eq([[entry.id]])
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
Expand All @@ -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
Expand Down
Loading

0 comments on commit af5271e

Please sign in to comment.