through rails many how has_and_belongs_to_many has foreign example create belongs and active ruby-on-rails ruby polymorphic-associations nested-attributes

ruby on rails - rails - accepts_nested_attributes_for con belongs_to polymorphic



rails foreign key (4)

Acabo de descubrir que los rieles no admiten este tipo de comportamiento, así que se me ocurrió la siguiente solución alternativa:

class Job <ActiveRecord::Base belongs_to :client, :polymorphic=>:true, :autosave=>true accepts_nested_attributes_for :client def attributes=(attributes = {}) self.client_type = attributes[:client_type] super end def client_attributes=(attributes) self.client = type.constantize.find_or_initialize_by_id(attributes.delete(:client_id)) if client_type.valid? end end

Esto me permite configurar mi formulario de esta manera:

<%= f.select :client_type %> <%= f.fields_for :client do |client|%> <%= client.text_field :name %> <% end %>

No es la solución exacta, pero la idea es importante.

Me gustaría establecer una relación polimórfica con accepts_nested_attributes_for . Aquí está el código:

class Contact <ActiveRecord::Base has_many :jobs, :as=>:client end class Job <ActiveRecord::Base belongs_to :client, :polymorphic=>:true accepts_nested_attributes_for :client end

Cuando intento acceder a Job.create(..., :client_attributes=>{...} me da NameError: uninitialized constant Job::Client


La respuesta anterior es excelente, pero no funciona con la configuración que se muestra. Me inspiró y pude crear una solución de trabajo:

funciona para crear y actualizar

class Job <ActiveRecord::Base belongs_to :client, :polymorphic=>:true attr_accessible :client_attributes accepts_nested_attributes_for :client def attributes=(attributes = {}) self.client_type = attributes[:client_type] super end def client_attributes=(attributes) some_client = self.client_type.constantize.find_or_initilize_by_id(self.client_id) some_client.attributes = attributes self.client = some_client end end


También he tenido un problema con "ArgumentError: no se puede construir la asociación model_name. ¿Estás tratando de construir una asociación polimórfica de uno a uno?"

Y encontré una mejor solución para este tipo de problema. Puedes usar el método nativo. Veamos la implementación de los atributos anidados, dentro de Rails3:

elsif !reject_new_record?(association_name, attributes) method = "build_#{association_name}" if respond_to?(method) send(method, attributes.except(*UNASSIGNABLE_KEYS)) else raise ArgumentError, "Cannot build association #{association_name}. Are you trying to build a polymorphic one-to-one association?" end end

Entonces, ¿qué tenemos que hacer aquí? Es solo para crear build _ # {association_name} dentro de nuestro modelo. He hecho un ejemplo totalmente funcional en la parte inferior:

class Job <ActiveRecord::Base CLIENT_TYPES = %w(Contact) attr_accessible :client_type, :client_attributes belongs_to :client, :polymorphic => :true accepts_nested_attributes_for :client protected def build_client(params, assignment_options) raise "Unknown client_type: #{client_type}" unless CLIENT_TYPES.include?(client_type) self.client = client_type.constantize.new(params) end end


Finalmente conseguí que esto funcionara con Rails 4.x. Esto se basa en la respuesta de Dmitry / ScotterC, entonces +1 a ellos.

PASO 1. Para comenzar, aquí está el modelo completo con asociación polimórfica:

# app/models/polymorph.rb class Polymorph < ActiveRecord::Base belongs_to :associable, polymorphic: true accepts_nested_attributes_for :associable def build_associable(params) self.associable = associable_type.constantize.new(params) end end # For the sake of example: # app/models/chicken.rb class Chicken < ActiveRecord::Base has_many: :polymorphs, as: :associable end

Sí, eso no es nada nuevo. Sin embargo, podría preguntarse, ¿de dónde viene polymorph_type y cómo se establece su valor? Es parte del registro de la base de datos subyacente, ya que las asociaciones polimórficas agregan las columnas <association_name>_id y <association_name>_type a la tabla. Tal como está, cuando build_associable ejecuta, el valor de _type es nil .

PASO 2. Pase y acepte el tipo de niño

Haga que su vista de formulario envíe el child_type junto con los datos de formulario típicos, y su controlador debe permitirlo en su verificación de parámetros fuertes.

# app/views/polymorph/_form.html.erb <%= form_for(@polymorph) do |form| %> # Pass in the child_type - This one has been turned into a chicken! <%= form.hidden_field(:polymorph_type, value: ''Chicken'' %> ... # Form values for Chicken <%= form.fields_for(:chicken) do |chicken_form| %> <%= chicken_form.text_field(:hunger_level) %> <%= chicken_form.text_field(:poop_level) %> ...etc... <% end %> <% end %> # app/controllers/polymorph_controllers.erb ... private def polymorph_params params.require(:polymorph).permit(:id, :polymorph_id, :polymorph_type) end

Por supuesto, su (s) vista (s) necesitarán manejar los diferentes tipos de modelos que son ''asociables'', pero esto demuestra uno.

Espero que esto ayude a alguien por ahí. (¿Por qué necesitas pollos polimórficos de todos modos?)