Reputation: 7220
I have Attraction
and Venue
models. Their associations are:
Attraction
belongs_to :venue
Venue
has_many :attractions, dependent: :nullify
I'm using the friendly_id
gem to add slugs to both. They are added with:
Attraction
friendly_id :slugged_name_and_venue, use: :slugged
Venue
friendly_id :slugged_name_and_location, use: :slugged
The problem I have is that, because the Attraction slug contains the name
and location_1
attributes of the venue
association, if the name
or location_1
attributes get changed, then the slug of the Attraction is incorrect. I need them to be updated to always stay in sync.
I know the concept of slugs is to keep one unique consistent string that never changes. I understand this, but this is not how i need this to work.
I know that including values from associations in a slug is also a bad idea, but in this case I need this. I don't typically do this.
I've tried a varying number of options, but none of them actually successfully get the associated Attraction slugs to update.
My latest attempt is this:
Venue
def should_generate_new_friendly_id?
slug.blank? || name_changed? || location_1_changed?
end
after_update :update_attraction_slugs, if: :should_update_attraction_slugs?
private
def should_update_attraction_slugs?
saved_change_to_name? || saved_change_to_location_1?
end
def update_attraction_slugs
attractions.find_each(&:save)
end
Attraction
def should_generate_new_friendly_id?
slug.blank? || slug_changed? || name_changed? || full_name_changed? || venue_id_changed? || venue_name_or_location_1_changed?
end
def venue_name_or_location_1_changed?
saved_change_to_attribute?(:venue_id) || venue.saved_change_to_name? || venue.saved_change_to_location_1?
end
Is anyone able to help me out here?
Upvotes: 0
Views: 70
Reputation: 30121
Just make sure your methods return true
when needed.
class Venue < ApplicationRecord
has_many :attractions, dependent: :destroy
after_update :update_attraction_slugs, if: :should_update_attraction_slugs?
def should_update_attraction_slugs?
saved_change_to_name? || saved_change_to_location_1?
end
def update_attraction_slugs
attractions.find_each(&:save)
end
end
class Attraction < ApplicationRecord
extend FriendlyId
belongs_to :venue
friendly_id :slugged_name_and_venue, use: :slugged
def slugged_name_and_venue
"#{venue.name} #{venue.location_1}"
end
# `saved_change_to_attribute?(:venue_id)` doesn't work on creation
def should_generate_new_friendly_id?
venue_id_changed? || venue.saved_change_to_name? || venue.saved_change_to_location_1?
end
end
>> Venue.create!(name: "ven1", location_1: "loc1")
=> #<Venue:0x00007fd62fbaf650 id: 6, name: "ven1", location_1: "loc1">
>> Venue.first.attractions.create!
=> #<Attraction:0x00007fd62fd15bc0 id: 1, venue_id: 6, slug: "ven1-loc1">
# ^^^^^^^^^
>> Venue.first.update!(name: "ven2")
Venue Load (0.2ms) SELECT "venues".* FROM "venues" ORDER BY "venues"."id" ASC LIMIT ? [["LIMIT", 1]]
TRANSACTION (0.1ms) begin transaction
Venue Update (0.4ms) UPDATE "venues" SET "name" = ? WHERE "venues"."id" = ? [["name", "ven2"], ["id", 6]]
Attraction Load (0.1ms) SELECT "attractions".* FROM "attractions" WHERE "attractions"."venue_id" = ? ORDER BY "attractions"."id" ASC LIMIT ? [["venue_id", 6], ["LIMIT", 1000]]
Attraction Exists? (0.1ms) SELECT 1 AS one FROM "attractions" WHERE "attractions"."id" != 1 AND "attractions"."slug" = ? LIMIT ? [["slug", "ven2-loc1"], ["LIMIT", 1]]
Attraction Exists? (0.1ms) SELECT 1 AS one FROM "attractions" WHERE "attractions"."id" != 1 AND "attractions"."slug" = ? LIMIT ? [["slug", "ven2-loc1"], ["LIMIT", 1]]
Attraction Update (0.1ms) UPDATE "attractions" SET "slug" = ? WHERE "attractions"."id" = ? [["slug", "ven2-loc1"], ["id", 1]]
TRANSACTION (0.1ms) commit transaction
=> true
>> Venue.first.attractions
=> [#<Attraction:0x00007fd62fba7810 id: 1, venue_id: 6, slug: "ven2-loc1">]
# ^^^^^^^^^
Upvotes: 1