私は比較的複雑なクロスワード ソルバー Rails アプリを作成していますが、この問題は、相互に作用する 2 つのモデル (Crossword と Cell) にのみ関連しています。
計画:
クロスワードを作成する前に、(行 * 列) に等しい数のセルを入力します。次に、そのパズルのすべてのセルが入力された後、各セルはそれに隣接するセルに関連付けられます。
Cell クラスの要約版を次に示します。.assign_bordering_cells
各セルには、メソッドによって設定された隣接セルとの相互関係があることに注意してください。
class Cell < ActiveRecord::Base
....
has_one :right_cell, class_name: 'Cell', foreign_key: 'left_cell_id', inverse_of: :left_cell
has_one :below_cell, class_name: 'Cell', foreign_key: 'above_cell_id', inverse_of: :above_cell
belongs_to :left_cell, class_name: 'Cell', foreign_key: 'left_cell_id', inverse_of: :right_cell
belongs_to :above_cell, class_name: 'Cell', foreign_key: 'above_cell_id', inverse_of: :below_cell
def assign_bordering_cells!
puts "Assign bordering cells for cell in row #{self.row}, column #{self.col}"
self.left_cell = self.crossword.cells.find_by_row_and_col(self.row, self.col-1) unless (self.col == 1)
self.above_cell = self.crossword.cells.find_by_row_and_col(self.row-1, self.col) unless (self.row == 1)
self.save
end
end
そして、これがクロスワードクラスの要約です。セルにデータを入力した後、.link_cells
メソッドはそれらすべてのセルを反復処理し、それらを隣接するセルにリンクする必要があります。
class Crossword < ActiveRecord::Base
before_create :populate_cells
after_create :link_cells
...
def populate_cells
row = 1
while (row <= self.rows)
col = 1
while (col <= self.cols)
self.cells << Cell.new(row: row, col: col, is_across_start: col == 1, is_down_start: row == 1)
col += 1
end
row += 1
end
end
def link_cells
self.cells.each {|cell| cell.assign_bordering_cells! }
end
end
最終結果は、各セルがその上、下、左、右にあるセルを「認識」する必要があります。これらの隣接セルの 1 ~ 2 個が欠落している可能性があるエッジ セルを考慮しました。
ヒッチ:
データベースに新しいクロスワードをシードすると、セルが正しく作成されます。ただし、.link_cells
は確実に呼び出され.assign_bordering_cells!
、セルごとに 1 回トリガーされますが、Cell-Cell 関連付けは保存されません。
データベースをシードした後で Crossword.first.link_cells を実行すると、すべてのセルが完全にリンクされます。まったく同じプロセスですが、1 つは:after_create
フィルターで発生しており、もう 1 つは Rails コンソールに入力しています。
質問:.link_cells
クロスワードを作成した後、Rails コンソールでは機能するのに、:after_create
クロスワード オブジェクトのフィルターでは機能
しないのはなぜですか?