Вопрос

Пытаюсь разобраться в этом уже больше дня, и я уверен, что это что-то простое, чего мне не хватает.

У меня есть проект, который может иметь одну основную категорию и две дополнительные категории.Мой соответствующий код для модели проекта:

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 и какие методы в нем есть?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top