Rails Dependent Update On Associated Record - oop

Given two associated models in rails (4.0),
class User < ActiveRecord::Base
has_one :subscription, dependent: :destroy
end
class Subscription < ActiveRecord::Base
belongs_to :user
end
The above code will ensure that when an instance of User is destroyed, its associated record will be, too.
So far so good.
My question is, is it possible to equally easily invoke a dependent update as well, so that every time User is updated, Subscription will be updated as well?
This could look like this:
class User < ActiveRecord::Base
has_one :subscription, dependent: [:update, :destroy]
end
So that when User gets updated successfully, the associated Subscription will re-save, thus invoking its update filters (i.e. before_save, before_update, after_save, after_update).
Is there an elegant way to do this? If not, what is the closest way to cleanly get to this?
Thank you!

Try this,
has_one :subscription, :dependent => destroy, :autosave => true
For more details see the documentation http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html

Related

Reverse merge for an active record

I'm facing an Rails (and finally a pur SQL) issue.
I have 3 tables (models). Event / User / Invitation
class Event < ApplicationRecord
has_many :invitations
end
class User < ApplicationRecord
has_many :invitations
has_many :events, through: :invitations
end
class Invitation < ApplicationRecord
belongs_to :event
belongs_to :user
end
I want to list all events where a specific user does not have invitation.
Contraints (very important in my case):
I'm starting my request by Event.
Basically, I would say it's the opposite of a merge, like a merge.not(user.events).
The only solution I found is:
Event.where.not(id: user.events.pluck(:id))
But obviously, I don't like it. 2 queries that might be somehow merge into a single one.
Any idea?
use select instead of pluck, it will create sub-query instead pulling records from database. Rails ActiveRecord Subqueries
Event.where.not(id: user.events.select(:id))

Returning associations for specific model when there is a polymorphic association in Rails 3.2

I have a polymorphic association in a Rails 3 app where a User may favorite objects of various classes.
class Favorite < ActiveRecord::Base
belongs_to :user
belongs_to :favoriteable, :polymorphic => true
end
class User < ActiveRecord::Base
has_many :favorites
end
class Image < ActiveRecord::Base
has_many :favorites, :as => :favoriteable
end
class Video < ActiveRecord::Base
has_many :favorites, :as => :favoriteable
end
I would like to be able return a list of just a User's favorite_images for example.
user.favorite_images #returns a list of the images associated with the user via :favoritable
I'm guessing there is a straightforward way of doing this but I haven't been able to figure it out. Let me know if you need anymore info.
Thanks!
===edit====
I know that I could retrieve what I am looking for via
favorite_images = user.favorites.collect{|f| if f.favoriteable_type=='Image'; f.favoriteable; end}
I could define an instance method for the User class and put that inside. I was wondering if there is a way to do it as some sort of has_many association. Really just because going forward it would be easier to have all that in one place.
When you created the table for Favorite you created a couple of columns favoriteable_id and favoriteable_type and you can use this information to restrict your query.
If you do user.favorites you will get all of the favorites and to restrict them to say just the images then you can do user.favorites.where(favoriteable_type: 'image') but that just gives you the favorite records and it sounds like you want the actual images. To get those you can do it by then mapping and pulling the favoriteable out. You'll likely want to include it in the query though so you don't hit the database so much. I would also make this a method on User.
def favorite_images
favorites.includes(:favoriteable).where(favoriteable_type: 'Image').map(&:favoriteable)
end

Unique Association :through

I have a many to many :through relationship between a set of classes like so:
class Company
has_many :shares
has_many :users, :through => :shares, :uniq => true
end
class User
has_many :shares
has_many :companys, :through => :shares, uniq => true
end
class Share
belongs_to :company
belongs_to :user
end
I want to ensure a unique relationship so that a user can only have one share in any one company, which is what I have tried to achieve using the "uniq" argument.
At first I thought this was working, however it seems the behaviour os the "uniq" is to filter on the SELECT of the record, not pre-INSERT so I still get duplicate records in the database, which becomes an issue if I want to start dealing with the :shares association directly, as calling user.shares will return duplicate records if they exist.
Can anyone help with an approach which would force truely uniq relationships? so that if I try adding the second relationships between a user and a company it will reject it and only keep the original?
Have you tried adding this to your Share class?
validates_uniqueness_of :user, scope: :company
Also, in your User class I think it should be:
has_many :companies, through: :shares
I hope that helps.

Building an active record with associations to two belongs_to relationships

Going back to an example I had previously asked about, I'll try and make this question as simple as possible.
Supposed I have User and Document models.
A User has_many Documents and a Document belongs_to a User. This relationship works fine today.
I want to introduce an Edits model that belongs_to a Document and belongs_to a User. The User can be any user, not necessary the one who created the document. With this new model, the Document now has_many :edits and the User has_many :edits.
So far it would look like:
# user.rb
class User < ActiveRecord::Base
has_many :edits
has_many :documents
end
# document.rb
class Document < ActiveRecord::Base
belongs_to :user
has_many :edits
end
# edit.rb
class Edit < ActiveRecord::Base
belongs_to :user
belongs_to :document
end
When I create a Document through a User, the association between the User and Document are fine in both directions (user.documents and document.user)
Now when I want to create an Edit, the edit should be against a Document but should also be associated with the user who generated the edit (edit.user).
When I'm building this in my RSpec tests I'm struggling to get the associations correct using the "standard" association methods. If I do #user.edits.build({...}) it will associate the user in the returned Edit object, but not the Document. Likewise when I do #document.edits.build({...}) it will associate the Document but not the User.
I supposed I could expose the user_id and post_id in the attr_accessible declaration but won't this but I fear this is not a best way of doing this. I have no real reason to fear other than the attributes are now accessible through mass assignment (from what I understand).
Am I going about this the wrong way or is there a better way to create and test all the associations?
class User < ActiveRecord::Base
has_many :edits, :through => :documents
has_many :documents
end

Filter based on model attribute has_many relationship through, rails 3?

I have a simple question, but can't seem to find any solution, though I have found things that are similar, but just not exactly what I am looking for.
I have an application where a User has many Assets through the class UserAsset. I want to be able to do current_user.user_assets , but I only want to return records that have an Asset with a specified field value of "active".
This post is similar but I need to use the main model not the join model as a filter.
class UserAsset < ActiveRecord::Base
belongs_to :asset
belongs_to :user
end
class Asset < ActiveRecord::Base
has_many :user_assets
has_many :users, :through => :user_assets
end
class User < ActiveRecord::Base
has_many :user_assets
has_many :assets, :through => :user_assets
end
I tried setting the default scope on Asset, and also some conditions on the has many (user_assets) relationship, but rails is failing to consider the join on the Assets table. ie Unknown column 'asset.live' in 'where clause'. Trying to achieve the following:
#active_user_assets = current_user.user_assets #only where assets.active = true
So how do I use conditions or scopes to achieve this? I need the user_asset object because it contains info about the relationship that is relevant.
Thanks in advance!
You want current_user.assets, then your scopes should work.
Oh, but you want the user_assets. Hmm. I think you need the :include clause to find() but where to put it, I can't be arsed to think of right now.
Perhaps
current_user.user_assets.find(:all, :include => :assets).where('asset.live=?', true)
(I'm not on Rails 3 yet, so that's going to be mangled)
Are you using :through when you really want a HABTM?