Form couldn't direct to edit path - ruby-on-rails

I have a form in the edit file under the related view folder. I want to direct this form to the editing route.
Here is my form,
<%= form_with(model: #trade, local: true) do |form| %>
<%= form.button "Accept", name: "button_action", value: "accept" %>
<%= form.button "Deny", name: "button_action", value: "decline" %>
<% end %>
My edit action in related controller,
def edit
#trade = Trade.find(params[:id])
if params['button_action'] == 'accept'
#trade.update(status: 1)
else
#trade.update(status: 2)
end
redirect_to root_path
end
And my routes,
book_trades GET /book/:book_id/trades(.:format) trades#index
POST /book/:book_id/trades(.:format) trades#create
new_book_trade GET /book/:book_id/trades/new(.:format) trades#new
edit_book_trade GET /book/:book_id/trades/:id/edit(.:format) trades#edit
book_trade GET /book/:book_id/trades/:id(.:format) trades#show
PATCH /book/:book_id/trades/:id(.:format) trades#update
PUT /book/:book_id/trades/:id(.:format) trades#update
DELETE /book/:book_id/trades/:id(.:format) trades#destroy
But I couldn't direct and get no route matches error. I'm new to ruby and programming, what's the point I'm missing?
Thanks in advance.

The edit method is for rendering the form. The form action will send a PUT request to the update method.
You need to keep the move the logic in the edit method to the update method

Related

Rails 6 create order confirmation before submit

I'm trying to create an order confirmation page for my Rails 6 app. The idea is that user will see a preview of the item they are creating before submitting and the object being saved in the database. Below desired flow:
User visits /cash_transactions/withdrawals/new
User enters data and clicks submit
User is redirected to /cash_transactions/withdrawals/confirm which
displays the entry
User clicks confirm to save object to db or cancel
Object is saved
I followed two main threads that describe this type of action, but they are quite old - 11 and 12 years old. Nevertheless based on that I've created below code:
# controllers/cash_transactions/withdrawals_controller.tb
module CashTransactions
class WithdrawalsController < CashTransactions::BaseController
(...)
def confirm
#cash_transaction = CashTransaction.new(cash_transaction_params)
render 'cash_transactions/_confirm'
end
end
end
# routes.rb
namespace :cash_transactions do
resources :withdrawals, only: %i[new create] do
collection do
post :confirm
end
end
end
With corresponding views:
# app/views/cash_transactions/new.html.erb
<%= render 'cash_transactions/form', cash_transaction: #cash_transaction %>
# views/cash_transactions/_form
# the form is rendered for cash_transaction create action
<%= simple_form_for cash_transaction, url: { action: :confirm } do |f| %>
<%= f.input :amount %>
<%= f.button :submit, 'Submit' %>
<% end %>
# confirmation page under views/cash_transactions/_confirm.html.erb
<div>
Total of withdrawal: <%= #cash_transaction.amount.to_i %>
</div>
<%= link_to 'Confim', cash_transactions_withdrawals_path(#cash_transaction), method: :post %>
<%= link_to 'Cancel', cash_transactions_path %>
And everything works until the user clicks confirm button in views/cash_transactions/_confirm.html.erb - instead of creating a record an error appears:
param is missing or the value is empty: cash_transaction
Did you mean?
authenticity_token
action
controller
_method
where did I go wrong? or there is a completely different way to do so?
tl/dr: You need to add parameters to your create request.
Why this is happening
The /confirm view is being rendered with an (unsaved) #cash_transaction object, however that object is not being used and so the information is being lost when the page is rendered.
The line:
<%= link_to 'Confim', cash_transactions_withdrawals_path(#cash_transaction), method: :post %>
Will submit a POST request with no parameters to the /cash_transactions/withdrawals#create (because you've given it no parameters to post). It doesn't know to include the params from the previous request.
There are a few options to fix this... you can add params as URL parameters in link_to like this, however I wouldn't recommend posting with params in the URL.
You can use button_to instead, and pass in the cash_transaction arguments from the previous request in the params: option (or pull them out of the unsaved #cash_transaction object).
Approach #1 - reuse create params
# Get them from the params sent in the previous request. In the controller...
def create
#cash_transaction = CashTransaction.create!(cash_transaction_params)
# etc...
end
#...
protected
def cash_transaction_params
params[:cash_transaction].permit(:amount, :whatever)
end
helper_method :cash_transaction_params
# In the view
<%= button_to 'Confirm', {action: 'create', params: cash_transaction_params}
Approach #2 - Access attributes from the model you built
<%= button_to 'Confirm', {action: 'create', params: #cash_transaction.attributes.slice('amount', 'other_attribute') }
Or you could do something like render the form again but hidden and have the "confirm" button submit the hidden form (with { action: :create } instead of { action: :confirm}). This last solution is probably the easiest to understand.

How to assign parameters and different controller method to button_to in Rails?

I am surprisingly having a hard time making button_to work the way I want to in Rails. I am inside users show page (localhost:3000/users/1). I want to create an availability (availability_controller.rb) from there. I have a create method inside availability controller.
Here is the availability controller:
def create
#availability = current_user.availability.build(available_on: Date.today, available_hour: params[:available_hour])
if #availability.save
flash[:notice] = "New availability added!"
redirect_to current_user
else
flash[:error] = "Error adding availability"
redirect_to current_user
end
end
It takes in a params, available_hour.
I was, fortunately, able to create a form to do what I need using form method:
<form method="post" action="/availability">
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
<button name="available_hour" value=0 type="submit" class="nowhere-block">Add Availability</button>
</form>
I hardcoded value of 0 to be sent to availability create method whenever user clicked on the button. This works great and I can probably go on with life.
However, I thought the code above is a little verbose, I wanted to achieve the same thing with button_to. I have looked at the button_to docs but I could not find the information I am looking for.
I tried <%= button_to "Post Availability", #availability, { available_hour: 5 } %> but it gave me No route matches [POST] "/users/1" error. Somehow it is still accessing user path.
I have tried other combinations as well unsuccessfully:
<%= button_to "Post Availability", availability_path, {controller: "availability", available_hour: 5 } %>
<%= button_to "Post Availability", #availability, remote: true, class: "nowhere-block" %>
How can I, from inside user show, access availability controller's create method?
Update:
Current routes.rb:
devise_for :users
resources :users
resources :friendships
resources :availability
root to: "users#index"
availability_index GET /availability(.:format) availability#index
POST /availability(.:format) availability#create
new_availability GET /availability/new(.:format) availability#new
edit_availability GET /availability/:id/edit(.:format) availability#edit
availability GET /availability/:id(.:format) availability#show
PATCH /availability/:id(.:format) availability#update
PUT /availability/:id(.:format) availability#update
DELETE /availability/:id(.:format) availability#destroy
You are passing a parameter wrong, also if you want to use #availability have to be defined in users_controller#show as #availability = Availability.new
Answer
<%= button_to "Post Availability", availability_path(available_hour: 5) %>
#or
<%= button_to "Post Availability", Availability.new, params: {available_hour: 5} %>
Try this
<%= button_to "Post Availability", availability_path(available_hour: 5) %>

Publish method doesn't work properly

I have an Entry model with a boolean column published, which is set to false by default. I wrote the following method in the model:
def self.publish
self.update(published: true)
end
and in my controller I have
def publish
#entry = Entry.find(params[:id]
#entry.publish
redirect_to entries_path
end
(I thought to make it similar to the calling of destroy method in the model). Finally, in my view I have this:
<%= link_to "Publish", entries_path, method: :publish %>
But when I click the link, the request is processed by create method and returns me the following error:
ActionController::ParameterMissing in Multiflora::EntriesController#create
param is missing or the value is empty: entry
The method is wrong in link_to as per the API so you have to mention one of valid Http methods (patch preferred in your case) , and then edit your route.rb file to transfer this patch request to your specified function like this:
patch'/entries/publish', to: 'entries#publish'
then change the "entries_path" to "entry_path"
so link code should look like this:
<%= link_to "Publish", entry_path, method: :patch%>
First thing, there is no HTTP method called :publish it should be :put or :patch
Second you need to pass id as parameter
<%= link_to "Publish", publish_entry_path(#entry) %>
Also you will need to add route for publish action
resources :events do
member do
put :publish
end
end
publish method should be instance method
def publish
self.update(published: true)
end
Thanks for all the answers, I've figured out what was my mistake, but I took a little think and decided to make it much more simple: I just added a checkbox to edit form, that sets :published attribute of entry true. Here it is:
<%=form_for(#entry, as: :entry, url: content_entry_path(#entry)) do |f| %>
# ...
<p>
<%= f.label "Publish" %> <br />
<%= f.hidden_field :published, value: '' %>
<%= f.check_box :published, checked: true %>
</p>
<% end %>
Anyways a lot of thanks for your answers! That was my lack of knowledge and I'll remember what have I done wrong

Rails Call Custom Controller Action from Custom Form

In a Rails project, I have the following controller action for the controller exchanges.rb:
def update_ordid
# Get the active exchange
#exchange = Exchange.find(params[:id])
# Decide which order ID field to update
active_order_field = params[:ordfld]
# Save the order ID
order_id = params[:ordid]
if active_order_field == 1 then
#exchange.order_id_1 = order_id
else
#exchange.order_id_2 = order_id
end
#active_exchange.save
respond_with(#exchange)
end
I've set up a route to this controller action:
resources :exchanges do
collection do
get 'update_ordid'
end
end
I want to call this action that accepts an order ID from a form on an exchanges show.html.erb page. I need to pass three values:
The ID of the current exchange, such as the integer in this example URL localhost:3000/exchanges/2 (This is the page the form is on)
The order ID as input from a text-field
Which of the two possible exchange fields the action should update
Next I need to create a custom form which will pass these values as parameters to the action. I haven't been able to find a good tutorial on how to do this yet, but my first thought was to set up the following:
<%= form_for(#exchange) do |f| %>
<div class="field">
<%= f.label :ordid, "Order ID" %><br>
<%= f.text_field :ordid, class: "form-control" %>
</div>
<% if #isrequestor == true %>
<%f.hidden_field :ordfld, :value => "1" %>
<% else %>
<%f.hidden_field :ordfld, :value => "2" %>
<% end %>
<div class="actions">
<%= f.submit "Submit", class: "btn btn-primary" %>
</div>
<% end %>
This gives me a NoMethodError stating the method 'ordid' is undefined. I'm guessing I need to modify the first line of code to associate the form with the custom action I've set up, but have no idea how to do so properly.
Yah, I got your point. So you wanted the following thing:
You wrote an custom action
You wanted to submit a form that action
You have registered your action in the router.
So let me answer the following solutions and find some mistakes you made in your code.
# in route.rb
resources :exchanges do
patch :update_ordid, on: :member # this is the best practice I would say,
#when you are trying to modify an existing record. So this action will only
#be reached with patch http methods
# on :member action an parameter id is required.
end
now if you generate your routes by running:
bundle exec rake routes
you will see a path like:
update_ordid_exchange /exchange/:id/update_ordid # :id parameter for exchange record
in your form set the url:
<%= form_for(#exchange, url: update_ordid_exchange_path) do |f| %>
or
<%= form_for(#exchange, url: url_for(controller: :exchange, action: update_ordid)) do |f| %>
Now then you will this form can submit this values within the parameter in your desire field.
So let me summarize things up here:
1. Setup your route properly
2. Check the url based on your route by generating rake routes command as shown above
3. Set the proper url and check if http method is correctly define in your form helper. For member actions, form helper by default use patch as http method. you just have to set the url.
Hope you understand my flow.

Rails update method for updating records not working

I have two methods in PersonsController- edit and update and a Person model:
def edit
#person=Person.find(params[:id])
end
def update
#person=Person.find(params[:id])
#person.update_attributes(params[:person])
end
and my edit.html.erb:
<h2> Edit info here!</h2>
<%= #person.name %>
<%= form_for #person, html: {mulitpart: true} do |f| %>
<p><%= f.text_field :location %></p>
<p><%= f.submit :submit , class: "btn btn-large btn-success" %></p>
<% end %>
and routes.rb:
resources :persons
But when I submit the form I get:
AbstractController::ActionNotFound
The action '5231d2491dba7fb057000004' could not be found for PersonsController
The 5231....... is id of a person.
Request Parameters:
{"utf8"=>"✓", "_method"=>"put", "authenticity_token"=>"3TL7nn4UxhxFoxETeooBMThhkE0VdMoGFpjN9sx4srk=", "person"=>{"location"=>"nagpur"}, "commit"=>"submit", "controller"=>"persons", "action"=>"5231d2491dba7fb057000004"}
What is wrong here? I'm using mongoid and rails 3.2.13.
Your final comment reveals the source of error.
For either #edit or #update, you should not set the params manually in hidden field, which is also unnecessary.
If using conventional RESTful routes as resources :persons, you edit route will look like GET /persons/1/edit where 1 is the param id. You can get this person in #edit as
#person = Person.find(params[:id])
Similarly, you can get the person again in #update whose route is PUT persons/1
#person = Person.find(params[:id])
Then the question is answered.
But there is one more problem in your code, the part you get the attributes for updating. Because the params of person's attributes are sent via form, all attributes are under params[:person]. Thus, to get the photo attribute, you should use
params[:person][:photo] # Not params[:photo]

Resources