what could cause a rails scope to throw a NoMethodError - mysql

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.

Related

Rails find object id on has_many association

I'm trying to get the transaction id associated with the current_user but rails shos this error below
error:
ActiveRecord::RecordNotFound (Couldn't find Transaction with id=92
[WHERE "transactions"."user_id" = 24])
iv'e tried use where and just the transaction and with a conditional comparing the transaction.user_id with the current_user.id but show error!
someone have any hint about this kind of issue?
model user
user has_many transactions
model transaction
transaction belongs to user
transaction controller
def new
#transaction = Transaction.new
end
def create
#transaction = Transaction.build_user
end
def show
#transaction = current_user.transactions.find(params[:id])
end
As many pointed in comments build_user does indeed create a new User instance (without saving it). Furthermore I believe build_user is not a class method but an instance method instead. Therefore Transaction.build_user should be raising 'undefined method' exception. Also, build_user returns a User instance, so even if you're code was #transaction = Transaction.new.build_user #transaction would be a newly created User instance.
And again, what others already pointed out in comments, your transaction wouldn't necessarily be associated to the current_user for you to fetch it like this in subsequent calls during the same session, rather, and supposing you properly built and saved the user, you would need to login as this 'new user' in order to.

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.

Rails 3 scope association error when using lambda

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) }

activerecord: update object attribute without using transaction

Here is my code:
class UserTopicVisit < ActiveRecord::Base
belongs_to :user
belongs_to :topic
def self.log_last_user_topic_visit(user_id, topic_id)
visit = UserTopicVisit.find_or_create_by_user_id_and_topic_id(user_id, topic_id)
visit.update_attributes!(:last_visit => Time.now.to_formatted_s(:db))
end
end
Which is self-explainig.
The problems is: I need to be able to update object attribute without transaction, by simple mysql query. How can I accomplish that using activerecord?
update_attributes uses a transaction, but oddly, save doesn't, so if you want callbacks and all that jazz without the transaction you can do:
visit.last_visit = Time.now.to_formatted_s(:db)
visit.save!
Under the hood, update_attributes actually just calls attributes= and then save.
Maybe you are looking for update-column
Updates a single attribute of an object, without calling save
Validation is skipped.
Callbacks are skipped.
updated_at/updated_on column is not updated if that column is available.