Rails nested attributes with a join model, where one of the models being joined is a new record
I'm trying to build a grid, in rails, for开发者_运维问答 entering data. It has rows and columns, and rows and columns are joined by cells. In my view, I need for the grid to be able to handle having 'new' rows and columns on the edge, so that if you type in them and then submit, they are automatically generated, and their shared cells are connected to them correctly. I want to be able to do this without JS.
Rails nested attributes fail to handle being mapped to both a new record and a new column, they can only do one or the other. The reason is that they are a nested specifically in one of the two models, and whichever one they aren't nested in will have no id (since it doesn't exist yet), and when pushed through accepts_nested_attributes_for on the top level Grid model, they will only be bound to the new object created for whatever they were nested in.
How can I handle this? Do I have to override rails handling of nested attributes?
My models look like this, btw:
class Grid < ActiveRecord::Base
has_many :rows
has_many :columns
has_many :cells, :through => :rows
accepts_nested_attributes_for :rows,
:allow_destroy => true,
:reject_if => lambda {|a| a[:description].blank? }
accepts_nested_attributes_for :columns,
:allow_destroy => true,
:reject_if => lambda {|a| a[:description].blank? }
end
class Column < ActiveRecord::Base
belongs_to :grid
has_many :cells, :dependent => :destroy
has_many :rows, :through => :grid
end
class Row < ActiveRecord::Base
belongs_to :grid
has_many :cells, :dependent => :destroy
has_many :columns, :through => :grid
accepts_nested_attributes_for :cells
end
class Cell < ActiveRecord::Base
belongs_to :row
belongs_to :column
has_one :grid, :through => :row
end
I faced a similar issue just a few days ago, and from what I could see there is no way around the dual nesting issue. I got beyond it by changing my "mental" model of the problem. In looking back at what I did and translating it to your situation, here is the approach I took:
class Grid < ActiveRecord::Base
has_many cells
has_many rows :through => :cells
has_many columns :through => :cells
accepts_nested_attributes_for :cells, :allow_destroy => true
end
class Cell
has_one column
has_one row
belongs_to grid
end
class Column
has_and_belongs_to_many cells
end
class Row
has_and_belongs_to_many cells
end
You will get some of the functionality you want via statements/methods like:
a_row = Grid.cells.where("row_id = a_cell.row_id")
def remove # an instance method for Row
self.cells.each do |cell|
cell.delete
end
end
def add_column # an instance method for Grid
self.column_count += 1
self.row_count.times do |i|
cell.new(:column_id => :self.column_count, :row_id => :i)
cell.save
end
end
Many of the column and row oriented operations that you want to perform on your grid will need to be accomplished with methods and scopes you write to create collections of cells that have a row_id or column_id in common.
Not sure if this will work for your case exactly, but it might help you with some different model approaches. Good luck.
精彩评论