Why I can't send a post method in RoR? - ruby-on-rails

I have this method to post the value to the "/store/add_to_cart"
<form action = "/store/add_to_cart" method="post">
<% for product in #products -%>
<div class = "entry">
<%= product.title %>
<%= product.price %>
<p>
</div>
<% end %>
<%= select( "payment", "id", { "Visa" => "1", "Mastercard" => "2"}) %>
<%= submit_tag 'Make Order' %>
</form>
In the /store/add_to_cart.html.erb, I created :
<%= params.length %>
<% for i in params%>
<%=i%>
<br/>
<% end %>
But I get this error:
ActionController::InvalidAuthenticityToken in StoreController#add_to_cart
What's happen? but after I change it to the get method, I can get all the params, wt's happen?

You are not using rails form_for helper to generate the <form> HTML markup, what this method does in addition is to add a hidden input field that is used to prevent CSRF attacks.
You have three options:
Use the form_for, form_tag... helper
Include the hidden input yourself
Disable the CSRF support

Related

Rails 5 fields_for only sends last params

I have been hitting my head against a brick wall so it is time to seek smarter people.
I am trying to create multiple records of one model using form_tag and fields_for. I have been following all the help/issues/guides I can find but it doesn't seem to work for me. I am wondering if it something that changed going to Rails 5 but more likely it is me.
Basically I want a new/create version of the task system listed at the bottom of the api page, similar to this guys puppy creator.
The "new" page loads fine with as many records as I like, so that part is ok but it doesn't seem to be creating a collection to send through, it is just overriding and thus sending through the last set of params so only creating one record.
What I have.
# routes
resources :container_returns
controller
# container returns controller
def new
#containers = Container.where(id: params[:container_ids])
#container_returns = []
#containers.each do |container|
#container_returns << ContainerReturn.new(
{
container_id: container.id,
quantity: container.amount,
uom: container.uom,
material_restriction_id: container.material_restriction_id
}
)
end
end
view
# new.html.erb
<%= form_tag container_returns_path, method: :post do %>
<% #container_returns.each do |container_return| %>
<%= fields_for 'returns[]', container_return, hidden_field_id: true do |cr| %>
<div class="field">
<%= cr.label :container_id %>
<%= cr.number_field :container_id %>
</div>
<div class="field">
<%= cr.label :material_restriction_id %>
<%= cr.number_field :material_restriction_id %>
</div>
<div class="field">
<%= cr.label :quantity %>
<%= cr.text_field :quantity %>
</div>
<div class="field">
<%= cr.label :uom %>
<%= cr.text_field :uom %>
</div>
<% end %>
<% end %>
<%= submit_tag "lots of returns" %>
<% end %>
which submits
# params submitted
Started POST "/container_returns" for 127.0.0.1 at 2018-10-19 11:00:48 +0200
Processing by ContainerReturnsController#create as HTML
Parameters: {
"utf8"=>"✓", "authenticity_token"=>[removed],
"returns"=>{"container_id"=>"405", "material_restriction_id"=>"", "quantity"=>"100.0", "uom"=>"kg"}, "commit"=>"lots of returns"
}
hopefully it is just something stupid that I missed.
UPDATE:
if I add an index to the form it now believes me that my objects are different and sends through all the params I need.
<% #container_returns.each_with_index do |container_return, index| %>
<%= fields_for 'returns[]', container_return, index: index do |cr| %>
[...]
as mentioned in the update, if I add an ID to the initial create it builds the correct array that I was expecting. What I also found was if I send through an index position that also works.
<% #container_returns.each_with_index do |container_return, index| %>
<%= fields_for 'returns[]', container_return, index: index do |cr| %>
[...]
gives me what I was expecting
Parameters: {
"returns"=>{"0"=>{"container_id"=>"400",...},
"1"=>{"container_id"=>"401",...},
etc.
},
"commit"=>"lots of returns"
}

Render in a different order on the page breaks the routing

I have Challenges containing Puns, and it is possible to vote on puns. On the Challenge Show page, all puns are rendered and show their votes count. This is currently on the view page:
<%= render #challenge.puns.reverse %>
<br>
<div id="form">
<%= render "puns/form" %>
</div>
I want the puns form to appear above the items (puns) already submitted. But if swap them around, like this:
<div id="form">
<%= render "puns/form" %>
</div>
<%= render #challenge.puns.reverse %>
I get a controller error and pun.id is not suddenly not available and the voting link breaks.
No route matches {:action=>"upvote", :challenge_id=>"9", :controller=>"puns", :id=>nil}, missing required keys: [:id]
Here is the puns/form part that is causing the issue
<% if signed_in? %>
<% if current_user.voted_for? pun %>
<%= pun.votes_for.size %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% else %>
<%= link_to like_challenge_pun_path(#challenge, pun.id), method: :put do %>
<span class="heart_like">❤</span> <%= pun.votes_for.size %>
<% end %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% end %>
<% end %>
It is the like_challenge_pun_path that throws an error but I cannot understand why. I am declaring #challenge again here, so it should be able to get the id.
Here is the form for the puns:
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
<span class=".emoji-picker-container">
<%= f.text_area :pun_text, placeholder: "Add pun", data: { emojiable: true } %>
</span>
<%= f.submit %>
<% end %>
Also, here is my routes setup
resources :challenges do
resources :puns do
member do
put "like", to: "puns#upvote"
put "dislike", to: "puns#downvote"
end
end
end
and the corresponding action to upvote
def upvote
#pun = #challenge.puns.find(params[:id])
#pun.upvote_by current_user
redirect_to #challenge
end
Can anyone help?
I think the code is for the puns collection.
I assume the issue is that in the form you have something like:
#challenge.puns.build
So in #challenge.puns collection appears not persisted record (without id), so path for this model cannot be generated.
As a quick solution I suggest:
<%= render #challenge.puns.reverse.select(&:persisted?) %>
UPDATE:
As I assumed you have
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
You can also try:
<%= form_for([#challenge, Pun.new]) do |f| %>
Or solve it in the controller. But need to see controller code for it.

unable to retrieve data from a form in rails

i am trying to access the data from a form.
<% form_tag(:action => "test") do %>
<p>
Name:
<%= text_field_tag("name","web programmer") %>
</p>
<%= submit_tag ("Save data") %>
<% end %>
this form is in views/challenges/show.html
I have written this piece of code in challenges_controller
def test
#name = params[:name]
end
before_filter :test
now,If i try to access #name variable in views/challenges/show.html
heres the code for that part
<% if #name != null %>
<%= #name %>
<% end %>
I get the following error
"undefined local variable or method `null' "
i have addded the following route to my routes.rb
get 'challenges/test'
Can someone help me out with this issue?
You need to display your form so instead of using <% %> you need to use <%= %>, checkout this answer for differences between them. By default forms use POST verb and you have defined a route for GET request. Change your form to this:
<%= form_tag({action: :test}, {method: :get}) do %>
<p>
Name:
<%= text_field_tag("name","web programmer") %>
</p>
<%= submit_tag ("Save data") %>
<% end %>

Rails: Forms_For new post calling different controller on submit

I've been working on a social site using the Rails framework. I just finished setting up a form and was able to submit a couple subposts. It worked for a bit, but now when I submit a subpost using forms_for(#subpost), it attempts to submit a completely different form on a separate view. No clue why it would call a separate form that hasn't even been rendered but hoping someone can help.
SubPost Controller
class SubPostsController < ApplicationController
def create
#subpost = SubPost.new(sub_post_params)
if #subpost.save
Form I want to submit
<%= form_for(#subpost) do |z| %>
<%= render 'shared/error_messages', object: z.object %>
<div class="field">
<!--<input type="text" name="sub_post[user_id]" value="<%# current_user %>" style="display:none;"/>-->
<input type="text" name="sub_post[micropost_id]" value="<%= micropost_id %>" style="display:none;"/>
<%= z.text_area :content, placeholder: "What's on your mind?" %>
</div>
<%= z.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
Updated to answer question
So basically I have my users personal page which displays their feed displaying a form under each post to submit a subpost. On the actual show page, there is no partial or render for post form, but that is what gets called each time I submit to the subpost form. The controller for the users page has two variables that I use to render the posts and subposts, #post = #user.posts.build and #subpost = #post.sub_posts.build
You can do something like this:
#some_controller.rb
def some_method
#posts = Post.all
SubPost.new
end
In your form you can use url option to take form parameters to create action. Assuming your routes are nested you can do something like this:
<% #posts.each do |post| %>
<%= form_for :subpost, url: some_path(#user, post) do |z| %>
// you need to replace some_path(#user,post) by your path helper
<%= render 'shared/error_messages', object: z.object %>
<div class="field">
<%= z.hidden_field :post_id, value: post.id %>
<%= z.text_area :content, placeholder: "What's on your mind?" %>
</div>
<%= z.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>

Rails not showing error on form submit

I am working in rails 2, I have a form containing data of two models, In one model I am validating fields and entering error using self.errors.add_to_base , but this is not displaying error on form and submitting that request successfully.
This is my Model validation\
validate :checkPunchingEntries
def checkPunchingEntries
if self.punch_in_time.blank? && self.punch_out_time.blank?
self.errors.add_to_base("Both 'Punch in' and 'Punch out' time can not be blank")
end
end
This is my Form
<% form_tag '/punching_requests/create', :method => :post, :class=>"punching_request_form" do %>
<% #punching_request.errors.full_messages.each do |msg| %>
<p class="error"><%=msg%></p>
<% end %>
<p>
<label>Date </label>
<%= text_field_tag 'date'%> <%= calendar_for("date") %>
</p>
<p>
<label> </label>
<input type="checkbox" onclick="punch_in_toggle()">Punch In</input>
<input type="checkbox" onclick="punch_out_toggle()">Punch Out</input>
</p>
<div id="punch_in">
<p>
<label>Punch In Time </label>
<%= text_field_tag 'punch_in_time'%>
</p>
</div>
<div id="punch_out">
<p>
<label>Punch Out Time </label>
<%= text_field_tag 'punch_out_time'%>
</p>
</div>
<p>
<label>Assign To</label>
<%= select_tag(:approved_by, options_from_collection_for_select(#human_resource_persons, "id", "login")) %>
</p>
<p>
<label>Reason </label>
<%=text_area_tag 'reason'%>
</p>
<p class="actions"><label></label><%= submit_tag 'Save' %></p>
<% end %>
It comes into validation, but error is not shown on validation fails.
Have you tried the IRB console? If not, take a look what is going on there, just to be sure, that #punching_request.errors contains something.
try this
def checkPunchingEntries
if self.punch_in_time.blank? && self.punch_out_time.blank?
errors[:base]<< "Both 'Punch in' and 'Punch out' time can not be blank"
end
end
and use form_for and #punching_request
for example
# in your controller
def new
#punching_request = PunchingRequest.new
end
def create
...
...
end
your form look like in your new.html.erb
form_for(#punching_request)
...
...
end
In this you're generating the form using form_tag and the errors you're expecting would be stored in the form builder,form_for.
Instead of form_tag use form_for(#punching_request). This should do the trick.

Resources