Problem with deletion and recreation of same association
I have a user model created through devise, a stock model (generated through a scaffold) so I can create a stocks database with my own custom prices, and a UserStock model to establish an association between the two. Everything seems to run fine in both my UI and my console.
Here's the catch.
I have a delete method tied to a button that is configured in my _list.html.erb, which displays all stocks in the user's portfolio. When I delete it the first time, (remove stock from my portfolio) it works fine. When I add the stock again to my portfolio, works fine of course. But the deletion the second time does not work.
Say, for example, my user ID is 1. My UserStock association creates an association between user_id 1 and stock_id 1 (say stock with id 1 is Google). This is stored in UserStock id 1. When I delete this association and recreate the same, it gets stored in UserStock id 2 (a brand new association). But when I try to delete it again, I'm unable to do so. My rails console indicates this error in my UserStock controller.
This is the error that pops up: Record Not Found in UserStocksController#destroy
def set_user_stock
@user_stock= UserStock.find(params[:id])
end
Here's my view and the required models:
_list.html.erb
<% if @user.id == current_user.id %>
<td>
<%=link_to "Delete", user_stock_path(user_stock), :method
=> :delete, :data => { :confirm => "Are you sure?" },
:class => "btn btn-xs btn-danger" %>
</td>
<% end %>
user.rb
has_many :user_stocks
has_many :stocks, through: :user_stocks
def can_add_stock?(ticker_symbol)
!stock_already_added?(ticker_symbol)
end
def stock_already_added?(ticker_symbol)
stock = Stock.find_by_ticker(ticker_symbol)
return false unless stock
user_stocks.where(stock_id: stock.id).exists?
end
stock.rb
has_many :user_stocks
has_many :users, through: :user_stocks
def self.find_by_ticker(ticker_symbol)
where(ticker: ticker_symbol).first
end
user_stock.rb
belongs_to :user
belongs_to :stock
The easiest way is to mimmic the flow in your console.
Check UserStock.last
and compare its details to the one you're trying to find after the second time.
BTW a few things that will make your code cleaner (in my personal opinion)
I would replace set_user_stock
by:
def set_user_stock
@user_stock= @user.user_stocks.find_by( id: params[:id])
if @user_stock.nil?
# do something , for example:
flash[:danger]= 'msg'
redirect_to 'path' and return
end
end
This will also remove the need for the if @user.id
condition since if some other user tries to touch another user stock , he will get redirected.
No need to define find_by_ticker
simply use Model.find_by( key_name: value)
, it will return the model or nil
.
Also , you can add a unique index
+ validation
on ticker_symbol
(or ticker_symbol && user_id
which make it easier to search/validate the checks you do.
Is this a typo?
<% if @user.id = current_user.id %>
You're assigning to @user.id
and not comparing ==
.
UserStock.last retrieves UserStock id:6, (user_id:1 and stock_id: 2) which means there have been over 5 associations created just by creating and deleting the same association. (I kept manually destroying the association in my console). I just deleted and recreated the same association again, and it allots UserStock id:7.
But when I try to use the destroy action in my UI, the rails console still tells me UserStock id:1 cannot be found.
How am I supposed to work around this?In your set_user_stock method, user_stocks is a method that isn't defined.
It'd be a pain to remove the method I created and then remove it everywhere but I'll do it when I'm in the process of refactoring code. Thanks for the heads up, didn't know I could directly call a Model.
Yes, it was a typo. Was in a hurry while typing out this question.
How do I go about this? Same error.
Add prints from inside the view
<% puts "user_id = #{@user.id} | current_user.id = #{current_user.id} | user_stock = #{user_stock.inspect}" %>
to see what is the content in the view.Your
user
model should haveuser_stocks
association on it, did you create aforeign
key reference?Yeah ,
where
usualy works on someActiveRecord
types. The variousfind*
methods are actually wrappers forwhere
. For examplefind_by
https://apidock.com/rails/v4.0.2/ActiveRecord/FinderMethods/find_by , although I'm missing alimit(1)
in those calls , that bothers me a little bit since if you know that youtake
the first only than you should alsolimit
theSQL
call.
Try #1 , to understand what's going on , the inconsistency must be in one of the 3 variables hence , start exploring them. puts
and inspect
are your friends :)
Nothing is displayed in the view when I add this line.
EDIT: When I look at my server logs the values returned from user_id, current_user.id and user_stock all seem to be correct. They're returning the values that are supposed to be returned.
UPDATE: Oops, on checking again, user_stock = #{user_stock.inspect}" is returning the Stock id in my console and NOT my user_stock association ID. So the fault lies in this variable. (In fact, this variable is returning the entire stock itself, with its name, ticker symbol and price) But isn't it supposed to be returning only the user_stock association ID?I just generated a migration to add foreign keys for user_stocks to user and stocks, but the user_stocks is still a method that is not defined. (this is what my console tells me)
EDIT: I think I know where I'm going wrong. The table is being iterated with the stocks association and not the user_stock association. I changed it to iterate through the user_stock end, but now how do I call the name, symbol and price variables within the table data?
I didn't understand the problem once you change the iterator.
Are you having any issue with <% user_stock.symbol %>
or anything similar?