has_many través de problema de actualización
-
23-08-2019 - |
Pregunta
estado tratando de resolver esto durante más de un día de estos, y estoy seguro de que es algo simple que me falta.
Tengo un proyecto, que puede tener una categoría principal y dos categorías opcionales. Mi código relevante para el modelo de proyecto:
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'
El código relevante de la clase Categoría:
has_many :project_categories
has_many :projects, :through => :project_categories, :source => :project
y de la clase ProjectCategory:
class ProjectCategory < ActiveRecord::Base
belongs_to :project
belongs_to :category
end
En mi punto 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>
y en mi controlador:
@project.attributes = params[:project]
Ok, por lo que al actualizar un proyecto existente, me sale el siguiente error:
undefined method `update_attributes' for #<Class:0x82efce0>
y el seguimiento de la pila correspondiente:
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'
¿Está diciendo que hay un problema con main_category y que es una clase genérica? ¿Pero por qué? La asociación define correctamente AFAIK.
Cualquier ayuda apreciada!
Vikram
Solución
Sé que esto no aborda el error que está recibiendo, pero me gustaría sugerir el uso de tres uno-a-muchas relaciones en lugar de uno a muchos-a-muchos relación.
El propósito convencional de has_many :through => ...
(muchos-a-muchos) es para cuando se tiene algo así como students
y classes
. Un estudiante puede estar en cualquier número de clases. Una clase puede tener cualquier número de alumnos. números totalmente arbitraria en ambos lados de la relación.
Pero eso no es su situación aquí. Sus proyectos pueden estar exactamente en una categoría principal, una categoría opcional 1, y una categoría opcional 2. Es un problema totalmente diferente y no es el problema que has_many :through
está diseñado para resolver.
Sugiero este arreglo:
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
A continuación, podrás hacer cosas como:
my_project.main_category
my_category.optional_category_1_projects
# etc...
Otros consejos
Tal vez cambiar el controlador a algo como:
@project = Project.find(params[:id])
@project.update_attributes(params[:project])
Es posible que necesite usar main_category_id
en su opinión, es decir.
Main Category: <%= f.select(:main_category_id, ...) %>
Usted está llamando update_attributes
, pero main_category
no es propiamente un atributo - es una asociación. main_category_id
es un atributo.
¿Dónde está usted recibiendo @project
de? ¿Usted apenas está haciendo un Project.find(params[:project_id])
normal o algo?
Intentó tirar en un comunicado debugger
y ver qué clase de la @project es y cuáles son los métodos que tiene en él?