Most idiomatic way to identify and modify an association directly

Suppose that we have Radio Stations which play Songs by means of a
License.

=======
class Song
has_many :licenses
has_many :radio_stations, :through => :licenses
end

class RadioStation
has_many :licenses
has_many :songs, :through => :licenses
end

class License
belongs_to :radio_station
belongs_to :song
end

Licenses are either active or not. Given a Song, we want to know which
Licenses are active. If that information was on Song instead, we could
just do something like:

scope :licensed_for_radio_station, lambda { |rs|

where(:licensed_stations => rs) }

But we can’t, since it’s on License instead. So, two questions:

1.) Given a Song, we want to know which Licenses are active.

What’s the most idiomatic way to do this? Association method? Scope?
etc.
2.) Given a Song and a RadioStation, what’s the most idiomatic way
to find the association that links them?
3.) Given a Song and a RadioStation, what’s the most idiomatic way
to modify the corresponding license to have :active => true?

Any thoughts are appreciated. Thanks!

~ jf

Off the top of my head, and with only one cup of coffee on board, I
suggest the following:

Since licenses can either be active or deactive, I assume there is a
boolean field behind it, in which case a scope would be handy:

class License
belongs_to :radio_station
belongs_to :song
scope :active, where => :active = true
end

This should allow you to perform the following:

song = Song.first
licences_for_song = song.licences.active

or even

licensed_stations = song.licences.active.radio_stations

If you already have the radio station, finding of it is listed should be
easy:

licensed_stations.include? radio_station

The last issue is a little more complex, but I think something along the
lines of:

License.where(:song => song).where(:radio_station =>
radio_station).activate!

Then create a method to respond (I am assuming the combined keys are
unique):

class License
belongs_to :radio_station
belongs_to :song
scope :active, where => :active = true

def activate!
update_attribute :active, true
end
end

Second cup of coffee kicked in.

You probably do not want to override the attribute “active” with the
scope I defined since it will prevent you from:

License.first.active?

And I am sure you will want that kind of functionality at some point.
Rename the scope to something else, perhaps:

scope :activated, where => :active = true

So song.licences.active.radio_stations becomes
song.licences.activated.radio_stations

Andrew S. <andrewskegg@…> writes:

Sorry,this is slightly wrong:

song = Song.first
licences_for_song = song.licences.active

It should be:

licences_for_song = song.licences.activated

And this can be optimised if you do not need all the licenses:

licensed_stations.include? radio_station

To:

license = song.licences.activated.where(:radio_station = radio_station)

John F. <johnf@…> writes:

has_many :licenses
Licenses are active. If that information was on Song instead, we could
2.) Given a Song and a RadioStation, what’s the most idiomatic way
to find the association that links them?
3.) Given a Song and a RadioStation, what’s the most idiomatic way
to modify the corresponding license to have :active => true?

Any thoughts are appreciated. Thanks!

~ jf

Since licenses can either be active or deactive, I assume there is a
boolean field behind it, in which case a scope would be handy:

class License
belongs_to :radio_station
belongs_to :song
scope :activated, where => :active = true
end

This should allow you to perform the following:

song = Song.first
licences_for_song = song.licences.active

or even

licensed_stations = song.licences.activated.radio_stations

If you already have the radio station, finding of it is listed should be
easy:

licensed_stations.include? radio_station

The last issue is a little more complex, but I think something along the
lines of:

License.where(:song => song).where(:radio_station =>
radio_station).activate!

Then create a method to respond (I am assuming the combined keys are
unique):

class License
belongs_to :radio_station
belongs_to :song
scope :activated, where => :active = true

def activate!
update_attribute :active, true
end
end