L.Wini
L.Wini

Reputation: 67

Rails destroy action doesn't work with button_to

I am a beginner in Rails and currently I am working on my project.The idea is, that when user buy something for someone, it can create a transaction with informations such us: for who it bought, how much it spent and finally a short description of transaction. I had created an admin column in database Users and initialized an admin user. I restricted access to index action only for admin - admin works fine. I want admin to be able to destroy transactions that are listed in the index view.What I wrote in order to achieve that does not work. Here is a screenshot of index view: https://i.sstatic.net/pK1Rg.png

My code in views/transactions/index

<ul>
 <% @transactions.each do |transaction| %>
  <li>
    <%= transaction.user_id %> | 
    <%= transaction.borrower_name %> | 
    <%= transaction.value %>
    <%= button_to "Delete", action: "destroy", method: :delete,
                            params: { transaction: { transaction_id: transaction.id } } %>
  </li>
 <% end %>
</ul>

My routes

Rails.application.routes.draw do
root 'static_pages#home'
get '/about',              to: 'static_pages#about'
get '/help',               to: 'static_pages#help'
get '/contact',            to: 'static_pages#contact'
get '/signup',             to: 'users#new'
get '/login',              to: 'session#new'
post '/login',             to: 'session#create'
delete '/logout',          to: 'session#destroy'
get '/transactions',       to: 'transactions#index'
post '/transactions/new',  to: 'transactions#create'
get '/transactions/new',   to: 'transactions#new'
post '/transactions/:id',  to: 'transactions#edit'
delete '/transactions',    to: 'transactions#destroy'
resources :users
resources :transactions
end

My controller

class TransactionsController < ApplicationController
  #skip_before_action :is_logged_in?, only: [:index]
  #before index and destroy action run check_admin -> ensure access only for admin user
  before_action :check_admin?, only: [ :index, :destroy ]


  def new
    @transaction = Transaction.new 
  end

  def create
    #current_user
    @transaction = current_user.transactions.build(transaction_params)
    #check if borrower_name exists in db - it must exists to make a transaction
    check = User.find_by(name: params[:transaction][:borrower_name])

    if check != current_user
      @transaction.save
      flash[:success] = "You have made a transaction!"
      redirect_to root_path
    elsif check == current_user
      flash[:danger] = "You try to make a transaction for yourself!"
      render 'transactions/new'
    else
      flash[:danger] = "Something went wrong!Probably, the borrower is not registed."
      render 'transactions/new'
    end  
  end

  def index
    @transactions = Transaction.all 
  end 

  def edit
    #get transactions where current_user borrows money from someone
    @transaction = Transaction.where(id: params[:transaction][:transaction_id])
    if params[:transaction][:active]
    @transaction.update(active: params[:transaction][:active], activated_at: Time.zone.now)
    else 
      @transaction.update(active: params[:transaction][:active])      
    end
    redirect_to transaction_path(current_user)
  end 

  def show 
    #grab the transactions assosiated with the user - 
    #user lends money - passive transactions

    if current_user
      #current_user lends money
      @lend_transaction = current_user.transactions  
      #current_user borrows money 
      @borrow_transaction = Transaction.where(borrower_name: current_user.name)     
    end

  end 


  def destroy 
    @transaction = Transaction.find(params[:transaction][:transaction_id])
    @transaction.destroy
    flash[:success] = "Transaction has been removed!"
    redirect_to transactions_path 

  end 


  private


  def transaction_params
    params.require(:transaction).permit(:borrower_name, :value)
  end 


  def check_admin?
    #check if current_user has admin => true
    redirect_to root_url unless current_user.admin
  end 

end

When I click on "Delete" here is what happens in logs: https://i.sstatic.net/A1HU8.png I get redirected to root_path - weird, look at the create action. I don't understand why it says "Unpermitted parameter: :transaction_id". I also don't understand why after I click on "Delete" a flash with message: "You have made a transaction!" occurs.Such flash should occur in create action. Here is the html:

I would appreciate any help.

Here is a helpers/session_helper code part related with current_user:

#method to determine a current user


module SessionHelper
  def current_user
    #if there is a session -> use session hash
    if session[:user_id]
      #nil or equal 
      @current_user ||= User.find_by(id: session[:user_id]) 
    #if there are cookies -> use cookies to operate log in 
    elsif cookies.encrypted[:user_id]
      #find the user by the encrypted user_id key
      user = User.find_by(id: cookies.encrypted[:user_id])
      #if user exists and the remember token authentication succeed
      #log in and set @current_user to user
      if user && user.authenticated?(cookies[:remember_token])
        log_in(user)
        @curent_user = user 
      end 
    end 
  end 

Upvotes: 0

Views: 739

Answers (1)

Violeta
Violeta

Reputation: 710

Welcome to SO @L.Wini.

For this particular issue, I'll suggest you couple things:

  1. In the routes file, you don't need these routes:
get '/transactions',       to: 'transactions#index'
post '/transactions/new',  to: 'transactions#create'
get '/transactions/new',   to: 'transactions#new'
post '/transactions/:id',  to: 'transactions#edit'
delete '/transactions',    to: 'transactions#destroy'

since you have: resources :transactions (this is generating all of them for you).

  1. In index.html.erb there's no need to use button_to:
<%= button_to "Delete", action: "destroy", method: :delete,
           params: { transaction: { transaction_id: transaction.id } } %>

Instead, you can use link_to:

<%= link_to 'Destroy', transaction, method: :delete, data: { confirm: 'Are you sure?' } %>
  1. The destroy action will accept params[:id] only:
def destroy 
  @transaction = Transaction.find(params[:id])
  @transaction.destroy
  flash[:success] = "Transaction has been removed!"
  redirect_to transactions_path
end 

This should help you solve the delete issue.

If you're interested in improving the code you have for the other actions, let me know and I'll try to help you out.

Happy coding!

Reference: https://guides.rubyonrails.org/action_controller_overview.html

Upvotes: 2

Related Questions