0

Following a tutorial on rails and I get this error when attempting a method: :delete action.

ActiveRecord::StatementInvalid (PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type integer

This is my destroy method.

  def destroy
@user_stock = current_user.user_stocks.where(stock_id: params[:id]).first
@user_stock.destroy
respond_to do |format|
  format.html { redirect_to my_portfolio_path, notice: "#{@user_stock.stock.ticker} was removed from portfolio." }
  format.json { head :no_content }
end
end

I read a question on here about find and find_by needing to be used right but it just confused me.

UserStocksController

class UserStocksController < ApplicationController
  before_action :set_user_stock, only: [:show, :edit, :update, :destroy]

  # GET /user_stocks
  # GET /user_stocks.json
  def index
    @user_stocks = UserStock.all
  end

  # GET /user_stocks/1
  # GET /user_stocks/1.json
  def show
  end

  # GET /user_stocks/new
  def new
    @user_stock = UserStock.new
  end

  # GET /user_stocks/1/edit
  def edit
  end

  # POST /user_stocks
  # POST /user_stocks.json
  def create
    if params[:stock_id].present?
      @user_stock = UserStock.new(stock_id: params[:stock_id], user: current_user)
    else
      stock = Stock.find_by_ticker(params[:stock_ticker])
      if stock
        @user_stock = UserStock.new(user: current_user, stock: stock)
      else
        stock = Stock.new_from_lookup(params[:stock_ticker])
        if stock.save
          @user_stock = UserStock.new(user:current_user, stock: stock)
        else
          @user_stock = nil
          flash[:error] = "Stock is not available"
        end
      end
    end
    
    respond_to do |format|
      if @user_stock.save
        format.html { redirect_to my_portfolio_path, notice: "Stock #{@user_stock.stock.ticker} was saved" }
        format.json { render :show, status: :created, location: @user_stock }
      else
        format.html { render :new }
        format.json { render json: @user_stock.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /user_stocks/1
  # PATCH/PUT /user_stocks/1.json
  def update
    respond_to do |format|
      if @user_stock.update(user_stock_params)
        format.html { redirect_to @user_stock, notice: 'User stock was successfully updated.' }
        format.json { render :show, status: :ok, location: @user_stock }
      else
        format.html { render :edit }
        format.json { render json: @user_stock.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /user_stocks/1
  # DELETE /user_stocks/1.json
  def destroy
    @user_stock = current_user.user_stocks.where(stock_id: params[:id]).first
    @user_stock.destroy
    respond_to do |format|
      format.html { redirect_to my_portfolio_path, notice: "#{@user_stock.stock.ticker} was removed from portfolio." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
  def set_user_stock
     @user_stock = UserStock.find_by(params[:id])
   end

    # Never trust parameters from the scary internet, only allow the white list through.
    def user_stock_params
      params.require(:user_stock).permit(:user_id, :stock_id)
    end
end

The my_portfolio view renders a partial _list

<table class="table table-striped">
	<thead>
		<tr>
			<th>Name</th>
			<th>Symbol</th>
			<th>Current Price</th>
			<% if @user.id == current_user.id%>
			<th>Actions</th>
			<%end%>
		</tr>
	</thead>
	<tbody>
		<%@user_stocks.each do |us|%>
		<tr>
			<td><%=us.name%></td>
			<td><%=us.ticker%></td>
			<td><%=us.price%></td>
			<% if @user.id == current_user.id%>
			<td>
				<%= link_to 'Delete', user_stock_path(us), :method => :delete,
					 									   :data => {:confirm => "You sure you want to delete #{us.name} from your portfolio?"},
														   :class => "btn btn-xs btn-danger"%>
            </td>
			<%end%>
		</tr>
		<%end%>
	</tbody>
</table>

2 Answers 2

1

Ok from what I have this my guess. Again, you only posted a partial so I am not sure how this all relates but my guess is that you add the id like this:

<%= link_to 'Delete', user_stock_path(id: us.id), :method => :delete,
                                                       :data => {:confirm => "You sure you want to delete #{us.name} from your portfolio?"},
                                                       :class => "btn btn-xs btn-danger"%>
Sign up to request clarification or add additional context in comments.

12 Comments

undefined method stock_id
Can you post your entire controller ?
just did that in my question
ActiveRecord::StatementInvalid (PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type integer still in heroku
Can you try the latest answer. If it does not work , please post your full trace
|
0

Your problem is probably your set_user_stock method:

def set_user_stock
  @user_stock = UserStock.find_by(params[:id])
end

UserStock.find_by(params[:id]) is just a shorter way of saying:

UserStock.where(params[:id]).first

So if params[:id] is, say, 6, you'll end up sending this SQL to the database:

select *
from user_stocks
where 6

and there's your error: 6 is not a boolean value in SQL and where 6 doesn't make sense. SQLite's interpretation of SQL is rather loose so it will accept nonsense like where 6 but PostgreSQL rightly complains.

There are two lessons here:

  1. Your set_user_stock method should look like:

    def set_user_stock
      @user_stock = UserStock.find(params[:id])
    end
    

    or

    def set_user_stock
      @user_stock = UserStock.find_by(:id => params[:id])
    end
    

    Use the find version if you're expecting to always call set_user_stock with a valid params[:id] and find_by if you want to deal with @user_stock.nil? yourself.

  2. Never ever develop on top of one database and deploy on another. Doubly so if you're trying to develop on SQLite and deploy on anything else. You should always develop, test, and deploy using the same database (all the way down to the database version), ActiveRecord will not protect you from any of the difficult parts of database portability.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.