veulent être en mesure d'attribuer une ville à un utilisateur, tant que l'utilisateur a été affecté au pays associé à la ville
Vous pouvez et vous ne devriez pas vouloir.
Créer un pays. Créez une ville et attribuez-la à un pays. Créez un voyage ou une visite, attribuez cette visite ou un voyage à une ville, puis ajoutez des utilisateurs à ce voyage ou à cette visite. Voila! vous avez la relation dont vous avez besoin! Je pense.
Une ville belongs_to un pays Un voyage belongs_to une ville Une visite belongs_to une ville A visites has_many utilisateur Un has_many utilisateur voyages Parce que les voyages et les visites appartient à une ville vous pouvez avoir has_many à travers les relations des deux côtés de la jointure donc les tables de visites et de voyages ont besoin de l'identifiant de la ville et de l'utilisateur Et vous avez les relations dont vous avez besoin et la logique dont vous avez besoin. N'essayez pas de faire des choses qui vont à l'encontre de vos exigences, comme de joindre directement des villes à des utilisateurs, car il est impossible d'assigner une ville à un utilisateur. En effet, juste pour vous donner un mal de tête encore plus grand, vous voudrez peut-être même avoir des voyages prenant de nombreuses visites dans de nombreuses villes dans de nombreux pays. Dans ce cas, vous souhaitez que les visites soient attribuées à un voyage et non à une ville.
Ceci est un problème logique et non un problème de codage.
MISE À JOUR En réponse aux commentaires
class User < ApplicationRecord
has_many :trips
has_many :cities, through: :trips
end
class Trip < ApplicationRecord
belongs_to :user
belongs_to :city
end
class City < ApplicationRecord
has_many :trips
has_many :users, through: :trips
end
puis dans la console
Loading development environment (Rails 5.1.4)
2.4.0 :001 > u = User.create(name: "Fred")
(0.0ms) begin transaction
SQL (0.3ms) INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "Fred"], ["created_at", "2017-09-17 14:24:30.720005"], ["updated_at", "2017-09-17 14:24:30.720005"]]
(16.3ms) commit transaction
=> #<User id: 1, name: "Fred", created_at: "2017-09-17 14:24:30", updated_at: "2017-09-17 14:24:30">
2.4.0 :004 > c = City.create(name: "Leeds")
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "cities" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "Leeds"], ["created_at", "2017-09-17 14:26:19.293166"], ["updated_at", "2017-09-17 14:26:19.293166"]]
(33.9ms) commit transaction
=> #<City id: 1, name: "Leeds", created_at: "2017-09-17 14:26:19", updated_at: "2017-09-17 14:26:19">
2.4.0 :005 > t = Trip.create(name: "T1", user: u, city: c)
(0.2ms) begin transaction
SQL (0.5ms) INSERT INTO "trips" ("user_id", "city_id", "name", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["user_id", 1], ["city_id", 1], ["name", "T1"], ["created_at", "2017-09-17 14:28:44.656390"], ["updated_at", "2017-09-17 14:28:44.656390"]]
(26.0ms) commit transaction
=> #<Trip id: 1, user_id: 1, city_id: 1, name: "T1", created_at: "2017-09-17 14:28:44", updated_at: "2017-09-17 14:28:44">
2.4.0 :006 > t.user.name#
=> "Fred"
2.4.0 :007 > t.city.name
=> "Leeds"
2.4.0 :008 > t.name
=> "T1"
Voilà comment une has_many normale à travers des œuvres, mais vous voulez une des villes has_many sur le modèle de voyages et je vais donc mettre à jour comment OK, pour atteindre la prochaine étape où un voyage a beaucoup de villes et une ville a_many voyages notez le has_many sur les deux côtés de la relation que vous êtes va avoir besoin d'une nouvelle table de référence croisée probablement appelée trip_city_xref qui a une clé primaire composée de city_id et trip_id
Ceci est dans les termes de Rails est une relation has_and_belongs_to_many que je déteste. C'est mon opinion seulement que has_and_belongs_to_many était sur la seule chose que Rails a eu tort. C'est un raccourci. D'autres ne seront pas d'accord, mais c'est comme cela que je l'établirais dans un langage qui n'aurait pas ce raccourci. Je pense que c'est plus clair et moins ambigu. Je voudrais donc mettre en place quelque chose comme ça
class Trip < ApplicationRecord
belongs_to :user
belongs_to: :city_trip_xref and
has_many :cities, through: :city_trip_xref
end
class City < ApplicationRecord
has_many :trips, through: :city_trip_xref
has_many :users, through: :trips
end
class CityTripXref < ApplicationRecord
belongs_to :trip
belongs_to :city
end
qui est juste mon avis alors ne hésitez pas à aller lire sur has_and_belongs_to_many here Alors que faites-vous avec votre utilisateur maintenant? Encore une fois, je mettrai à jour bientôt
MISE À JOUR User.cities Ainsi, votre modèle utilisateur pourrait ressembler à ceci
class User < ApplicationRecord
has_many :trips
has_many :city_trip_xrefs, through: :trips
def cities
trips.map(&:city_trip_xrefs).flatten.map(&:city)
end
end
Pour obtenir toutes les villes d'un utilisateur visite sur un voyage que vous pouvez aplatir et cartographier les relations comme si u = User.first u.trips.map (&: city_trip_xrefs) .flatten.map (&: ville)
alors vous pouvez faire une méthode sur votre classe utilisateur pour obtenir les villes en utilisant ce qui précède que montré dans le modèle de l'utilisateur ci-dessus. En ce qui concerne l'attribution d'une ville à un utilisateur, vous ne voudriez pas vraiment le faire directement de toute façon.Vous organisez un voyage, ajoutez des utilisateurs et des villes à ce voyage et vous avez toutes les fonctionnalités dont vous aurez probablement besoin dans un exemple réel à moins que vos exigences ne soient quelque peu différentes
Mettre tout cela ensemble en utilisant les enregistrements créés ci-dessus dans la console ainsi qu'un enregistrement de la table de city_trip_xref pour rejoindre le nombre de nombreux voyages vers les villes pour une ville existante et voyage, vous pouvez maintenant faire
d'abord créer la référence externe dans la console
ctx = CityTripXref.new
=> #<CityTripXref id: nil, city_id: nil, trip_id: nil, created_at: nil, updated_at: nil>
2.4.0 :008 > ctx.city = City.first
=> #<City id: 1, name: "Leeds", created_at: "2017-09-17 14:26:19", updated_at: "2017-09-17 14:26:19">
2.4.0 :009 > ctx.trip = Trip.first
=> #<Trip id: 1, user_id: 1, city_id: 1, name: "T1", created_at: "2017-09-17 14:28:44", updated_at: "2017-09-17 14:28:44">
2.4.0 :010 > ctx.save
suivant get le nom de la première ville lors du premier voyage du premier utilisateur
2.4.0 :028 > u = User.first
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "Fred", created_at: "2017-09-17 14:24:30", updated_at: "2017-09-17 14:24:30">
2.4.0 :029 > u.cities.first.name
Trip Load (0.1ms) SELECT "trips".* FROM "trips" WHERE "trips"."user_id" = ? [["user_id", 1]]
CityTripXref Load (0.1ms) SELECT "city_trip_xrefs".* FROM "city_trip_xrefs" WHERE "city_trip_xrefs"."trip_id" = ? [["trip_id", 1]]
City Load (0.1ms) SELECT "cities".* FROM "cities" WHERE "cities"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> "Leeds"
2.4.0 :030 >
Espérons que cela a du sens.
Pourriez-vous simplement créer deux tables de jointures standard: 'country_users' et' cities_users', et écrire une ** validation de modèle ** sur ce dernier pour affirmer que la ville a été assignée à l'utilisateur? –
Remarque: Vous avez probablement besoin d'une sorte de logique de pré- ou de post-suppression pour éviter qu'un utilisateur soit ** désaffecté ** d'un pays, mais reste assigné aux villes. (c'est-à-dire soit interdisez de telles suppressions, soit supprimez les autres associations dans le cadre de la transaction.) –
Vous ne pouvez pas affecter une ville à un utilisateur car un utilisateur possède plusieurs villes? Un utilisateur doit appartenir à une ville pour pouvoir attribuer une ville à un utilisateur! Ce que vous voulez vraiment, c'est attribuer des visites aux utilisateurs et affecter une ville à une visite. Mettez à jour votre question à celle qui a du sens et peut-être que je peux aider plus loin. Scrappez la simplification c'est vous causer des problèmes et vous faire croire que vous devriez être capable de faire des choses qui cassent vos exigences – jamesc