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.
Related
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.
I am creating a record and then pushing the id of the newly created record in a queue, from the after create filter.
From another script I am reading the ids from the queue and reading the db record for the ids instantly.
record = Model.find(id)# this is giving error: Couldn't find record with ID 8732
I am using rails 2.3.14 with mysql2 gem.
What you are experience is known as a race-condition.
Your second script or worker library is trying to access the record before it has been entirely written ("committed"), as ilan pointed out.
A common solution to this problem is using an after_commit callback instead of after_create / after_save etc.
An example from the Article on Rails BestPractices.
Before:
class Notification < ActiveRecord::Base
after_create :asyns_send_notification
def async_send_notification
NotificationWorker.async_send_notification({:notification_id => id})
end
end
class NotificationWorker < Workling::Base
def send_notification(params)
notification = Notification.find(params[:notification_id])
user = notification.user
# send notification to user's friends by email
end
end
After refactoring using after_commit lifecycle hooks:
class Notification < ActiveRecord::Base
after_commit :asyns_send_notification, :on => :create
def async_send_notification
NotificationWorker.async_send_notification({:notification_id => id})
end
end
Further reading: after_commit in the Rails API docs.
Maybe the query result "SELECT * FROM Model WHERE id=8732" is on cache.
You should try to "reload" the query :
record = Model.find_by_id(id, true)
The reason has to do with transaction isolation levels. Although you can read the entry that you just inserted, another process can't until the transaction is committed. This commit happens after the controller returns.
I am creating an auction house similar to eBay. My question is with my bids resource. It will keep track of all of the bids that are placed. However I MUST ensure that every new bid on an item, is higher than the current bid, otherwise that would defeat the purpose of an auction.
The way I currently want to do this is to create a transaction inside the bids controller, that would check whether or not the amount being bid for an item, is greater than the max of the other bids for the same item.
def create
bid.transaction
#bid = Bid.new(params[:bid])
#bid.user = current_user
#bid.item = current_item
# DO STUFF TO CHECK ITS GREATER THAN MAX OF BIDS FOR CURRENT_ITEM
# ON ERROR, ROLLBACK TRANSACTION AND THROW ERROR
end
end
I would definitely handle this in the model. Create a custom validation such as:
#Bid Model
validate :bid_is_higher_than_current_highest
private
def bid_is_higher_than_current_highest
bid > item.current_highest_bid
end
Something like that.
First off make sure you're using the InnoDB table type as MyISAM does not support transactions.
But you're basically right, you just want to run a query inside your transaction to determine the maximum bid:
max_bid_amount = Bid.where(:id => item.id).maximum(:bid_amount)
if #bid.bid_amount > max_bid_amount
# proceed with bid placement
else
# do something, return some flag, nil or whatever
end
Then check the value and proceed accordingly. I would think you would not want to raise an exception for flow control purposes.
I also recommend that you move this logic outside of the controller and either into the Model or some other management layer, maybe have a generic Ruby class like BidManager which contains the flow logic for bid placement.
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.
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.