update tutorial rails method example beginner ruby-on-rails ruby-on-rails-4

ruby-on-rails - tutorial - ruby on rails update controller



has_many: a través de class_name y foreign_key (2)

El problema aquí es que en

has_many :managers, through: :listing_managers

ActiveRecord puede inferir que el nombre de la asociación en el modelo join (: listing_managers) porque tiene el mismo nombre que has_many :through asociación que está definiendo. Es decir, tanto los listados como los list_mangers tienen muchos administradores .

Pero ese no es el caso en su otra asociación. Allí, un listing_manager tiene muchas has_many :listings , pero un usuario has_many :managed_listings . Entonces ActiveRecord no puede inferir el nombre de la asociación en ListingManager que debería usar.

Para esto es la opción :source (ver http://guides.rubyonrails.org/association_basics.html#has-many-association-reference ). Entonces la declaración correcta sería:

has_many :managed_listings, through: :listing_managers, source: :listing

(ps no necesitas las :foreign_key o :class_name en la otra has_many :through . Las :class_name para definir asociaciones directas , y luego todo lo que necesitas en una has_many :through es apuntar a la asociación correcta en el :through modelo.)

Estoy trabajando con una situación bastante sencilla de has_many through: donde puedo hacer que los parámetros class_name / foreign_key funcionen en una dirección pero no en la otra. Quizás puedas ayudarme. (ps estoy usando Rails 4 si eso hace una diferencia):

Inglés: un usuario gestiona muchos listados a través de ListingManager, y un listado es administrado por muchos usuarios a través de ListingManager. El administrador de listas tiene algunos campos de datos, que no guardan relación con esta pregunta, así que los edité en el siguiente código

Aquí está la parte simple que funciona:

class User < ActiveRecord::Base has_many :listing_managers has_many :listings, through: :listing_managers end class Listing < ActiveRecord::Base has_many :listing_managers has_many :managers, through: :listing_managers, class_name: "User", foreign_key: "manager_id" end class ListingManager < ActiveRecord::Base belongs_to :listing belongs_to :manager, class_name:"User" attr_accessible :listing_id, :manager_id end

Como puede adivinar desde arriba, la tabla de ListingManager se ve así:

create_table "listing_managers", force: true do |t| t.integer "listing_id" t.integer "manager_id" end

así que el único no simple aquí es que ListingManager usa manager_id lugar de user_id

De todos modos, lo anterior funciona. Puedo llamar a user.listings para obtener los Listings asociados con el usuario, y puedo llamar a listing.managers para obtener los administradores asociados con el listado.

Sin embargo (y esta es la pregunta), decidí que no era demasiado significativo decir user.listings ya que un usuario también puede "poseer" en lugar de "administrar" listas, lo que realmente quería era user.managed_listings así que puse user.rb para cambiar has_many: listados, a través de:: listing_managers a has_many: managed_listings, a través de:: listing_managers, class_name: "Listing", foreign_key: "listing_id"

Esta es una analogía exacta del código en listing.rb arriba, así que pensé que esto debería funcionar de inmediato. En cambio, mi prueba rspec de este barfs diciendo ActiveRecord::HasManyThroughSourceAssociationNotFoundError: Could not find the source association(s) :managed_listing or :managed_listings in model ListingManager. Try ''has_many :managed_listings, :through => :listing_managers, :source => <name>''. Is it one of :listing or :manager? ActiveRecord::HasManyThroughSourceAssociationNotFoundError: Could not find the source association(s) :managed_listing or :managed_listings in model ListingManager. Try ''has_many :managed_listings, :through => :listing_managers, :source => <name>''. Is it one of :listing or :manager?

la prueba es:

it "manages many managed_listings" do user = FactoryGirl.build(:user) l1 = FactoryGirl.build(:listing) l2 = FactoryGirl.build(:listing) user.managed_listings << l1 user.managed_listings << l2 expect( @user.managed_listings.size ).to eq 2 end

Ahora, estoy convencido de que no sé nada. Sí, creo que podría hacer un alias, pero me molesta que la misma técnica utilizada en listing.rb no parezca funcionar en user.rb ¿Puedes ayudar a explicar?

ACTUALIZACIÓN: actualicé el código para reflejar las sugerencias de @gregates, pero todavía me encuentro con un problema: escribí una prueba adicional que falla (y se confirma por "mano": prueba en la consola de Rails). Cuando uno escribe una prueba como esta:

it "manages many managed_listings" do l1 = FactoryGirl.create(:listing) @user = User.last ListingManager.destroy_all @before_count = ListingManager.count expect( @before_count ).to eq 0 lm = FactoryGirl.create(:listing_manager, manager_id: @user.id, listing_id: l1.id) expect( @user.managed_listings.count ).to eq 1 end

Lo anterior falla Rails genera el error PG::UndefinedColumn: ERROR: column listing_managers.user_id does not exist (debería estar buscando ''listing_managers.manager_id''). Así que creo que todavía hay un error en el lado del usuario de la asociación. En user.rb ''s has_many :managed_listings, through: :listing_managers, source: :listing , ¿cómo sabe el usuario usar manager_id para acceder a sus listados?


Sé que esta es una vieja pregunta, pero acabo de pasar un tiempo corriendo en los mismos errores y finalmente lo descubrí. Esto es lo que hice:

class User < ActiveRecord::Base has_many :listing_managers has_many :managed_listings, through: :listing_managers, source: :listing end class Listing < ActiveRecord::Base has_many :listing_managers has_many :managers, through: :listing_managers, source: :user end class ListingManager < ActiveRecord::Base belongs_to :listing belongs_to :user end

A esto se parece la tabla Join de ListingManager:

create_table :listing_managers do |t| t.integer :listing_id t.integer :user_id end

Espero que esto ayude a los buscadores futuros.