Rails tem muitos através de caixas de seleção polimórficas
-
25-09-2019 - |
Pergunta
Este está realmente me derrubando! :(
Estou tentando criar um formulário de modelo aninhado para o meu modelo de usuário com uma lista de seleção, onde várias lojas podem ser verificadas ou desmarcadas para administrar as lojas por meio do pessoal do modelo.
class Staffing < ActiveRecord::Base
# Associations
belongs_to :user
belongs_to :staffable, :polymorphic => true
belongs_to :store, :class_name => "Store",
:foreign_key => "staffable_id"
end
class User < ActiveRecord::Base
# Includes
acts_as_authentic
# Associations
has_many :staffings, :dependent => :destroy
has_many :stores, :through => :staffings
# Nested Attributes
accepts_nested_attributes_for :staffings, :allow_destroy => true
end
class Store < ActiveRecord::Base
# Associations
has_many :staffings, :as => :staffable, :dependent => :destroy
has_many :users, :through => :staffings
end
# Users Controller
def create
@user = User.new(params[:user])
flash.now[:notice] = "#{@user.name} was successfully created." if @user.save
respond_with @user
end
def update
@user = User.find(params[:id])
params[:user][:store_ids] ||= []
@user.update_attributes(params[:user])
flash.now[:notice] = "#{@user.name} was successfully updated."
respond_with @user
end
Para os propósitos em questão, a outra associação de equipe pode ser ignorada. É um modelo semelhante que eu gostaria de administrar ao lado da loja, mas a primeira coisa é a primeira, já que estou tão perplexo como é.
# User Form
- for store in Store.all
%p
= check_box_tag "user[store_ids][]", store.id, @user.stores.include?(store)
= store.nickname
Envia meus parâmetros como tal:
{"utf8"=>"✓",
"authenticity_token"=>"blub-blub-blub=",
"user"=>{"login"=>"hey.buddy",
"email"=>"test@hey.net",
"role"=>"admin",
"hq"=>"1",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]",
"store_ids"=>["3",
"4"]}}
E então erro!
Mysql2::Error: Column 'staffable_type' cannot be null: INSERT INTO `staffings` (`created_at`, `staffable_id`, `staffable_type`, `updated_at`, `user_id`) VALUES ('2010-11-17 00:30:24', 3, NULL, '2010-11-17 00:30:24', 102)
Eu sei que tenho que criar Staffable_type como 'loja', mas tenho tentado o dia todo-o que é o truque?
Eu tenho as colunas Staffable_type (e ID) definidas como: null => false, mas essa não pode ser a causa disso, pois isso precisa ser endireitado no controlador antes de atingir o banco de dados de qualquer maneira.
Por que o abaixo não funciona na minha ação de criação:
@user.staffings.each do |s|
s.staffable_type = 'Store'
end
ou:
@user.store_ids.each do |i|
s = @user.staffings.build
s.staffable_type = 'Store'
s.staffable_id = i
end
Se estiver tentando muitas coisas semelhantes às acima sem sucesso. Qualquer ajuda será extremamente apreciada.
Obrigado pelo seu tempo!
Solução
Ok, eu descobri isso. Estou respondendo aqui para que eu possa ajudar alguém algum dia, mas o problema foi uma supervisão básica sobre a diferença entre muitas e pertencem a muitas associações.
Você deseja lidar com caixas de seleção ou listas de múltiplas selecionas em A muitas, não existe um método '_ids' gerado para você pela associação e precisa escrever uma por si mesmo.
Veja o artigo de Paul Barry aqui:http://paulbarry.com/articles/2007/10/24/has_many-through-checkboxes
As coisas polimórficas podem ser complicadas, mas se você estiver preso, talvez dê um passo atrás e certifique-se de que não seja algo ainda mais básico que está bagunçando você- funcionou para mim!
Abaixo está o código modificado no blog de Paul sobre como lidar com isso se você estiver lidando com um polimórfico tem muitos (basicamente você só precisa usar o hash dos atributos e escrever seu atributo polymorphic_type):
attr_accessor :store_ids
after_save :update_stores
#after_save callback to handle group_ids
def update_stores
unless store_ids.nil?
self.staffings.each do |staffing|
staffing.destroy unless store_ids.include?(staffing.staffable_id.to_s)
store_ids.delete(staffing.staffable_id.to_s)
end
store_ids.each do |s|
self.staffings.create(attributes = {:staffable_id => s, :staffable_type => 'Store'}) unless s.blank?
end
reload
self.store_ids = nil
end
end