Rails 3 scope association error when using lambda - mysql

So trying to write a scope in my user model and I just can't seem to get it to work.
My user model looks sorta like this
class User < ActiveRecord::Base
has_one :user_profile
scope :api_user, lambda { |member_code| joins(:users, user_profiles).where('user_profiles.member_code = ?', member_code)}
And my user_profiles model looks like this:
class UserProfile < ActiveRecord::Base
belongs_to :user
When I call the scope in the rails console like so :
User.api_user(4321)
I get this error:
ActiveRecord::ConfigurationError: Association named 'users' was not found; perhaps you misspelled it?
I'm new to scopes and I know how to do this without them, if I do this:
User.find_by_id(UserProfile.find_by_member_code(4321).user_id)
It returns exactly what I want. But I'm going to need to use this multiple times, (writing an api) so I would really like to get the scope working.
Have looked over these questions here and here, but they didn't shed any light on my problem.

The joins only needs to list the association, and not itself. So it should look like this:
scope :api_user, lambda { |member_code| joins(:user_profile).where('user_profiles.member_code = ?', member_code) }

Related

Combining data from two tables in rails

I have two models, one belongs to the other. They look like this:
class LittleClass < ActiveRecord::Base
has_many :little_class_sessions
end
and
class LittleClassSession < ActiveRecord::Base
belongs_to :little_class
end
LittleClassSession has a column called little_class_id. I want to get all LittleClassSession but also have the associated LittleClass returned to me in the same hash.
Is there some way to do this that's built into Rails? Or is there a clean way to do this?
And is this something that I build into the LittleClass or LittleClassSession model with scope?
When you query ActiveRecord you will get an array of ActiveRecord:Relation. It is a specific entity which starts your query. You can of course join dependent tables (as in your example with one-to-many relation). But you will still need to go over those dependent relations to build whatever object you need.
Here is a sketch of what I mean (assume we search for all little class sessions with specific little class id):
class_sessions = LittleClassSession.includes(:little_class).where(:little_classes => {:id => 1})
class_sessions.each do |relation|
test_hash = relation.attributes.merge!({:little_class => relation.little_class.attributes});
puts test_hash
end
test_hash will include all the attributes of the little class session as well as attributes of the little class under corresponding key.

How to delete a record only if it exists in Rails?

I want to delete the tokens I created for a post, when I am deleting the post itself. But if the token does not exist, I don't want Rails to throw an error and stop executing.
Right now, this is how I go about it. I think this code is way too chunky. Is there any neat way to accomplish the same?
DownloadToken.find_by_post_id(post.id).destroy unless DownloadToken.find_by_post_id(#post.id).nil?
This is one way(old syntax)
DownloadToken.find_by_post_id(post.id).try(:destroy)
Newer syntax in rails:
DownloadToken.find_by(id: post.id).try(:destroy)
With Ruby's safe navigation operator:
DownloadToken.find_by(id: post.id)&.destroy
Look at your Post model; post.rb
Ie.
Class Post < ActiveRecord::Base
has_many :download_tokens, dependent: :destroy
end
Now when you delete a Post object, whatever the association; has_many, has_one, it will find the destroy the dependent also. In this case the DownloadToken(s)
DownloadToken.find_by_post_id(post.id)&.destroy
Executes destroy only if the query result is not nil. It's the abbreviated version of:
token = DownloadToken.find_by_post_id(post.id)
token.destroy if token
If you are certain you 'll handle the post deletion with its destroy method, than you can follow Jay's answer and it will work just fine.
If you will use the delete method on post you need some extra functionality to handle the download_tokens.
class DownloadToken < ActiveRecord::Base
def self.remove_post_tokens(the_post_id)
where(post_id: the_post_id).destroy_all
end
end
so your sequence will be:
id = post.id
post.delete #or post.destroy
DownloadToken.remove_post_tokens(id)
That scenario is not purely academic, because the dependent destroy action can be really expensive, eg if you have too many download_tokens, so you would not want it to be in the same transaction as post's destruction.

Save model id as foreign key through has_one / belongs_to

I'll briefly explain my situation: I have a model called "tax" which belongs_to a "user" and of which a "user" has_one.
In my users table I have a column called "tax_id" which I want to store the id of the tax model when a user creates one.
Currently, in my tax model the create function looks something like this:
class Tax < ActiveRecord:Base
belongs_to :user
tax = Tax.new(income: income, taxes: taxes, rrsp: rrsp)
tax.save
and then in the taxes_controller file, the create function looks like this:
def create
#tax = Tax.new(secure_params)
#tax.user = User.find(current_user.id)
if #tax.save
redirect_to show_tax_path(current_user.tax)
else
render :new
end
end
(secure_params) being the strong parameters for the field inputs set in a private definition.
Now, someone mentioned that I may have better luck if I use build but unfortunately I couldn't get it to work at all, something to do with how I'm using current_user (devise). Currently, my setup works just fine, other than saving the tax model id in the user model column "tax_id" like I said.
I'm wondering if I perhaps need to add a foreign ID key to either the belongs_to or has_one statement, even though I was under the impression that the "link" should be made automatically as long as the column was named "[model]_id"
try using
user.build_tax
I think this might help you out.
The build syntax for has_many association:
user.taxes.build
The build syntax for has_one association:
user.build_tax # this will work
user.tax.build # this will throw error

In Laravels Eloquent/Fluent, is there a way to delete a row and everything connected to it through relationships?

Basically, it would be really nice to delete something and have it automatically search out and delete all of the rows and fields connected to it, rather than having to do all of that manually.
For example, using eager loading, I can eager load like so:
Page::with(array(
'elements',
'elements.drafts',
'elements.content',
'elements.content.drafts'
))->where('myField', '=', $value)->first();
is there a way to do something similar for the delete operation? Something like:
Page::with(array(
'elements',
'elements.drafts',
'elements.content',
'elements.content.drafts'
))->where('myField', '=', $value)->delete();
Of course, I've tried the above code and it did not work. I'm providing it to help communicate what I'm looking for.
After a bit more searching I was able to figure it out! I'm far frame an SQL expert, so I didn't even know to search for a "CASCADE" delete, which is what it's called in SQL terms.
In any case, I found more information another StackOverflow post.
I ended up having to set up delete function throughout all of my relationships.
For has_many relationships
For has_many relationships I had to use the code from the other StackOverflow post. Specifically, like so:
// This code is in my elements model, which has_many content
public function delete()
{
foreach($this->content as $content)
{
$content->delete();
}
return parent::delete();
}
For has_one relationships
I do want to point out, however, that if you are dealing with a has_one relationship, you have to alter your code so that it looks like what is below.
// This is inside my content model, which has_one draft
public function delete()
{
// delete the single draft
$this->drafts()->delete();
return parent::delete();
}

what could cause a rails scope to throw a NoMethodError

What could cause a rails app to have a no method error when using a scope?
I have a basic user class that has cats and dogs. I will need to combine the queries and sort them by created date. Eventually the individual queries will be more complex.
class User < ActiveRecord::Base
has_many :dogs
has_many :cats
scope :pets, joins(:dogs).joins(:cats).order("created_at desc")
In view
<%= render #user.pets%>
Is causing an no method error
undefined method `pets' for #<User:0x00000106370cb0>
Scopes only define class methods on the ActiveRecord model. The proper way to call this would be on the User model directly. User.pets as opposed to an instance of User #user.pets.
What you could do is create a method to be called on a User instance.
def pets
User.joins(:dogs).joins(:cats).order("created_at desc")
end
And thus, #user.pets is allowed.