has_many проблема с обновлением
-
23-08-2019 - |
Вопрос
Пытаюсь разобраться в этом уже больше дня, и я уверен, что это что-то простое, чего мне не хватает.
У меня есть проект, который может иметь одну основную категорию и две дополнительные категории.Мой соответствующий код для модели проекта:
has_many :project_categories
has_one :optional_category_1,
:through => :project_categories,
:conditions => 'is_main_category = 0',
:order => 'category_id',
:source => :category,
:class_name => 'Category'
has_one :optional_category_2,
:through => :project_categories,
:conditions => 'is_main_category = 0',
:order => 'category_id DESC',
:source => :category,
:class_name => 'Category'
has_one :main_category,
:through => :project_categories,
:conditions => 'is_main_category = 1',
:source => :category,
:class_name => 'Category'
Соответствующий код из категории class:
has_many :project_categories
has_many :projects, :through => :project_categories, :source => :project
и из класса ProjectCategory:
class ProjectCategory < ActiveRecord::Base
belongs_to :project
belongs_to :category
end
На мой взгляд:
Main Category: <%= f.select(:main_category, Category.find(:all, :order => 'parent_id, categories.desc').collect {|c| [c.display_name, c.id] }, :prompt => "Select a Main Category") %><br>
Optional Category 1: <%= f.select(:optional_category_1, Category.find(:all, :order => 'parent_id, categories.desc').collect {|c| [c.display_name, c.id] }, :prompt => "Select an Optional Category") %><br>
Optional Category 2: <%= f.select(:optional_category_2, Category.find(:all, :order => 'parent_id, categories.desc').collect {|c| [c.display_name, c.id] }, :prompt => "Select an Optional Category") %><br>
и в моем контроллере:
@project.attributes = params[:project]
Хорошо, итак, при обновлении существующего проекта я получаю следующую ошибку:
undefined method `update_attributes' for #<Class:0x82efce0>
и соответствующая трассировка стека:
C:/Software/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/associations.rb:1255:in `main_category='
C:/Software/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:2745:in `send'
C:/Software/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:2745:in `attributes='
C:/Software/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:2741:in `each'
C:/Software/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:2741:in `attributes='
C:/Development/craftbits_rails/app/controllers/projects_controller.rb:85:in `manage_project'
Это говорит о том, что существует проблема с main_category и что это универсальный класс?Но почему?Ассоциация определяет это правильно AFAIK.
Любая помощь приветствуется!
Викрам
Решение
Я знаю, что это не устраняет ошибку, которую вы получаете, но я бы предложил использовать три отношения "один ко многим" вместо одного отношения "многие ко многим".
Общепринятое назначение has_many :through => ...
(многие ко многим) предназначен для случаев, когда у вас есть что-то вроде students
и classes
.Студент может быть в Любой количество классов.Класс может иметь Любой количество студентов.Абсолютно произвольные числа по обе стороны отношения.
Но это не ваша ситуация здесь.Ваши проекты могут относиться только к одной основной категории, одной необязательной категории 1 и одной необязательной категории 2.Это совершенно другая проблема, и это не та проблема, которая has_many :through
предназначен для решения.
Я предлагаю такую договоренность:
class Project < ActiveRecord::Base
belongs_to :main_category, :class_name => "Category",
:foreign_key => 'main_category_id'
belongs_to :optional_category_1, :class_name => "Category",
:foreign_key => 'optional_category_1_id'
belongs_to :optional_category_2, :class_name => "Category",
:foreign_key => 'optional_category_2_id'
end
class Category < ActiveRecord::Base
has_many :main_category_projects, :class_name => "Project",
:foreign_key => 'main_category_id'
has_many :optional_category_1_projects, :class_name => "Project",
:foreign_key => 'optional_category_1_id'
has_many :optional_category_2_projects, :class_name => "Project",
:foreign_key => 'optional_category_2_id'
end
Тогда вы сможете делать такие вещи, как:
my_project.main_category
my_category.optional_category_1_projects
# etc...
Другие советы
Может быть, сменить контроллер на что-то вроде:
@project = Project.find(params[:id])
@project.update_attributes(params[:project])
Возможно, вам потребуется использовать main_category_id
на ваш взгляд, т.е.
Main Category: <%= f.select(:main_category_id, ...) %>
Ты звонишь update_attributes
, но main_category
на самом деле это не атрибут - это ассоциация. main_category_id
является атрибутом.
К чему ты клонишь @project
откуда?Ты просто делаешь обычную Project.find(params[:project_id])
или что-то еще?
Пробовал бросать в debugger
заявление и посмотреть, что это за класс @project и какие методы в нем есть?