Pergunta

vindo a tentar resolver isso por mais de um dia agora, e tenho a certeza de que é algo simples que eu estou ausente.

Eu tenho um projeto, o que pode ter uma categoria principal e duas categorias opcionais. Meu código relevante para o modelo de projeto:

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'

O código relevante da classe Categoria:

has_many :project_categories
has_many :projects, :through => :project_categories, :source => :project

e da classe ProjectCategory:

class ProjectCategory < ActiveRecord::Base
  belongs_to :project
  belongs_to :category
end

No meu ponto de vista:

    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>

e no meu controlador:

      @project.attributes = params[:project]

Ok, então ao atualizar um projeto existente, recebo o seguinte erro:

undefined method `update_attributes' for #<Class:0x82efce0>

e o rastreamento de pilha relevante:

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'

É dizendo que há um problema com main_category e que é uma classe genérica? Mas por que? Os define associação corretamente AFAIK.

Qualquer ajuda apreciada!

Vikram

Foi útil?

Solução

Eu sei que isso não resolve o erro que você está recebendo, mas eu sugiro usar três one-to-muitos relacionamentos em vez de um muitos-para-muitos relação.

O objetivo convencional de has_many :through => ... (many-to-many) é para quando você tem algo como students e classes. Um aluno pode estar em qualquer número de classes. Uma classe pode ter qualquer número de alunos. números totalmente arbitrárias em ambos os lados da relação.

Mas isso não é a sua situação aqui. Seus projetos podem estar em exatamente uma categoria principal, uma categoria opcional 1, e uma categoria opcional 2. É um problema totalmente diferente e não é o problema que has_many :through é projetado para resolver.

Eu sugiro este arranjo:

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

Em seguida, você vai ser capaz de fazer coisas como:

my_project.main_category

my_category.optional_category_1_projects

# etc...

Outras dicas

Talvez mudar o controlador para algo como:

@project = Project.find(params[:id])
@project.update_attributes(params[:project])

Você pode precisar usar main_category_id na sua opinião, i.

Main Category: <%= f.select(:main_category_id, ...) %>

Você está chamando update_attributes, mas main_category não é propriamente um atributo - é uma associação. main_category_id é um atributo.

Onde você está recebendo @project de? Você está apenas fazendo um Project.find(params[:project_id]) normal ou algo assim?

Tentou jogar em um comunicado debugger e ver o que a classe do @project é e quais os métodos que tem sobre ele?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top