Rails ajax authenticity - ruby-on-rails

Hello guys I am developing an application in ruby on rails I am trying save the contents of a form through ajax
Here is the code of my form :
<%= form_for([#question, #question.answers.build],remote: true) do|f|%>
<h2>Link</h2>
<%= f.text_field :link ,:id=>'link'%>
<h2>Time</h2>
<p class="s-line">
<%= f.label :hh,"HH:" %>
<%= f.text_field :hh ,:id=>'hh'%>
<%= f.label :mm,"MM:" %>
<%= f.text_field :mm,:id=>'mm' %>
<%= f.label :ss,"SS:"%>
<%= f.text_field :ss,:id=>'ss' %>
<%= f.hidden_field :user,:value =>session[:username] %>
</p>
<%= f.submit "Answer" ,:class=>'btn btn-medium btn-success'%>
<% end %>
and the code of controller is :
def create
question = Question.find(params[:question_id])
#answer = question.answers.create(ans_params)
respond_to do |create|
create.js{}
end
end
an I was getting this error :
ActionController::InvalidAuthenticityToken
And I tried to solve this by putting this line
skip_before_action :verify_authenticity_token
to my controller.
now I am getting this error
ActionController::UnknownFormat
In this line
respond_to do |create|
Please help

I think the solution lies here:
<%= form_for([#question, #question.answers.build],remote: true) do|f|%>
Question
Why are you sending #question.answers.build with the #question var? IMO this is bad practice, and I'd do this:
<%= form_for #answer, remote: true do |f| %>
#config/routes.rb
resources :questions do
resources :answers, only: [:new, :create]
end
#app/controllers/answers_controller.rb
respond_to :html, :js: json
before_action :find_question, only: [:new, :create]
def new
#answer = #question.answers.build
end
def create
#answer = #question.answer.create(ans_params)
end
private
def find_question
#question = Question.find(params[:question_id])
end
def ans_params
params.require(:answer).permit(:attrs)
end
For your Ajax authentication issue - I believe it is a problem with how you're declaring & handling the data in your form. I would try the refactors I posted above & see if that helps

Related

Transmit params with form_tag

In my views I have a form and trying to update quantity for an order line:
<div class="quantity">Quantity</br>
<%= form_tag(order_line_path(line.id), method: "patch") do %>
<%= number_field_tag 'qty', '1', within: 1...line.book.stock %>
<%= submit_tag "Update", class: "btn btn-primary" %>
<% end %>
</div>
The instance variable in the rest of my view is a collection of order lines, so I cannot use it.
Then I have in my controller the update method:
def update
#order = current_order
#order_line = #order.order_lines.find(params[:id])
#order_line.update_attributes(order_line_params)
end
And my strong params definition:
def order_line_params
params.require(:order_line).permit(:qty)
end
I get this error :
param is missing or the value is empty: order_line
Could someone please have a look?
Thanks!
The reason you are getting param is missing or the value is empty: order_line is that you are using form_tag which gives a "flat" params hash.
However this is easily avoidable if you just use form_with/form_for.
# routes.rb
resources :orders do
resources :line_items, shallow: true
end
# app/views/order_items/edit.html.erb
# use `form_with(model: #order_item)` in Rails 5
<%= form_for(#order_item) do |f| %>
<%= f.label :qty, within: 1...f.object.book.stock %>
<%= f.number_field :qty, %>
<%= f.submit %>
<% end %>
class OrderItemsController < ApplicationController
before_action :set_order_item, only: [:show, :edit, :update, :destroy]
# ...
# GET /order_items/:id/edit
def edit
end
# PATCH /order_items/:id
def update
if #order_item.update(order_item_params)
redirect_to #order_item, notice: 'Line updated'
else
render :edit
end
end
private
def set_order_item
#order_item = OrderItem.find(params[:id])
end
def order_item_params
params.require(:order_item).permit(:qty)
end
end
But what you're really looking for unless you are doing the update/creation of nested items with AJAX is most likely a combination of accepts_nested_attributes and fields_for which will let the user mass edit the line items:
class Order < ApplicationRecord
accepts_nested_attributes_for :order_items
end
<%= form_for(#order) do |f| %>
<%= fields_for(:order_items) do |oif| %>
<%= f.label :qty, within: 1...f.object.book.stock %>
<%= f.number_field :qty, %>
<% end %>
<%= f.submit %>
<% end %>
class OrdersController < ApplicationController
# PATCH /orders/:id
def update
if #order.update(order_params)
redirect_to #order, notice: 'Order updated.'
else
render :new
end
end
private
def order_params
params.require(:order).permit(order_items_attributes: [:qty])
end
end

Rails - Passing a variable while using Simple Form

When creating a new model object using simple form, I need to pass the id of one object to the new object as it relies on the id for its URL. The routing is:
resources :coins do
resources :questions
end
I am attempting to do this using a hidden field tag but its not working. The ID is not passed and as a result, the new object does not save.
<%= simple_form_for #question, url: coin_questions_path(#coin.id) do |f| %>
<%= f.input :ques_num %>
<%= f.input :content %>
<%= hidden_field_tag(:coin_id, #coin.id) %>
<%= f.button :submit, 'Submit' %>
<% end %>
Prior to this, I was using collection_select in simple form to manually enter the ID and it worked, however I need it to happen automatically. Is there a better way of doing this that will do what I am looking for?
Question model:
class QuestionsController < ApplicationController
before_action :find_question, only: [:show, :edit, :update, :destroy ]
before_action :find_coin
before_action :authenticate_user!, except: [:index, :show]
def index
#questions = Question.where(coin_id: #coin.id).order("created_at DESC")
end
def show
end
def new
#coin
#question = current_user.questions.build
end
def create
#question = current_user.questions.build(question_params)
if #question.save
redirect_to coin_question_path(#coin.id, #question.id)
else
render 'new'
end
end
.
.
.
private
def find_question
#question = Question.find(params[:id])
end
def find_coin
#coin = Coin.find(params[:coin_id])
end
def question_params
params.require(:question).permit(:content, :ques_num, :coin_id)
end
end
You could easily use hidden_field with a value - read more
For example:
<%= f.hidden_field :coin_id, value: #coin.id %>
And then the value will be in the params[:question][:coin_id] on create, so the rest should work as it is now. :)
<%= hidden_field_tag(:coin_id, #coin.id) %> will generate a field with a name of just "coin_id"; you want "question[coin_id]"
You should, in turn, assign this value to the object in your controller. #question.coin_id = #coin.id, or #question = Question.new(:user => current_user, :coin => #coin) or #question = current_user.questions.new(:coin => #coin)
<%= f.input :coin_id, :as => :hidden %>

Rails 5 - Render New with Parameter

I have checked old similar post but but I'm still having problems.
When I create a new listing the URL looks as below:
http://localhost:3000/listings/new?plan=1
In the form_for I'm hiding some fields when plan=1
<%= form_for(#listing) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.hidden_field :plan, :value => #plan %>
<%= f.label :Title %>
<%= f.text_field :title, class: 'form-control' %>
<!-- don't show description for standard plan -->
<% if #plan != 1.to_s %>
<%= f.label :Description %>
<%= f.text_area :description, :rows => 10,
placeholder: "Describe your business...", class: 'form-control' %>
<% end %>
In the ListingsController I set the plan in before action:
before_action :set_plan, only: [:new, :create]
def set_plan
#plan = params[:plan]
end
so I can use it as hidden field on the form above.
My problem starts when I save the form with errors.
The new form URL changes to http://localhost:3000/listings.
I can see the #plan=1 still on the form:
<input value="1" type="hidden" name="listing[plan]" id="listing_plan" />
, but now the form is showing all fields (which should be hidden due to this condition <% if #plan != 1.to_s %>)
Actions in ListingsController:
def new
#listing = Listing.new
end
def create
#listing = current_user.listings.build(listing_params) if logged_in?
#plan = #listing.plan
if #listing.save
flash[:success] = "Listing created!"
redirect_to #listing
else
render 'new'
end
end
I have tried something like that but no success:
render :action => 'new', :plan => #listing.plan
and few other things
How can I hide those fields on error?
You should be able to solve this by modifying your ListingsController to set the plan on create. Specifically, in ListingsController.rb:
# app/controllers/listings_controller.rb
before_action :set_plan, only: [:new, :create]
Also, be sure your listing_params method permits :plan.
If you want this to function on update, then add :update to your before_action as well.
I have it fixed.
#plan = params[:plan]
was returning string (when the field in DB is integer), so I changed it to:
#plan = params[:plan].to_i
and now in the form I have the below for all actions:
<% if #plan != 1 %>

No route matches [POST] when submitting new form in Rails

I am getting a "No route matches [POST]" when submitting a new form.
### /routes.rb ###
resources :artists, controller: 'artists/artists', only: [:show] do
member do
resources :videos, controller: 'artists/videos', only: [:index, :new, :create, :edit, :update]
end
end
### /artists/videos/videos_controller.rb ###
class Artists::VideosController < ApplicationController
before_action :set_artist
def new
#video = ArtistVideo.new
end
def create
#video = #artist.create_artist_video(video_params)
if #video.save
redirect_to current_artist
else
render 'new'
end
end
private
def set_artist
#artist = current_artist
end
end
### /artists/videos/new.html.erb ###
<%= form_for(#video, url: new_video_path) do |f| %>
<%= f.label :video_title, "title", class: "label" %>
<%= f.text_field :video_title, class: "text-field" %>
<%= f.label :video_description, "decription", class: "label" %>
<%= f.text_field :video_description, class: "text-field" %>
<%= f.label :youtube_video_url, "youtube url", class: "label" %>
<%= f.text_field :youtube_video_url, class: "text-field" %>
<%= f.submit "add video", class: "submit-button" %>
<% end %>
### rake routes ###
videos_path GET /artists/:id/videos(.:format) artists/videos#index
POST /artists/:id/videos(.:format) artists/videos#create
new_video_path GET /artists/:id/videos/new(.:format) artists/videos#new
edit_video_path GET /artists/:id/videos/:id/edit(.:format) artists/videos#edit
video_path PATCH /artists/:id/videos/:id(.:format) artists/videos#update
PUT /artists/:id/videos/:id(.:format) artists/videos#update
So not sure what I'm doing wrong here. I've tried taking :index completely out so videos_path uses the post method, but I still have the same problem.
I'm using the has_many method linking videos to artists, if that even matters.
Not sure if it's the routs or the controller code that's wrong. Any help would be appreciated.
You're specifying a path url: new_video_path but that is for videos#new and what you want is the create path, which is a post to videos_path(#artist). Since it's a nested resource, the path has to have the artist_id which it can get from the #artist instance.
But, the simpler way to do this is like so:
form_for[#artist, #video] do |f|

Error: param is missing or the value is empty: thing

I'm using rails 4.0.8. I added a comment section to a model called 'Things', but I keep getting the same error "param is missing or the value is empty: thing" when I press the submit comment button. It says the error is in the Things#Controller. What am I doing wrong?
UPDATE: I removed the url path from the form, but a new error returns "Couldn't find Thing without an ID". The error is in Comments#Controller.
VIEW FOR THING/SHOW
<div id= "thing">
<h1>
<%= #thing.name %>
</h1>
<br>
<div id= "commentsection">
Comments
<div id= "comments">
<br>
<% #thing.comments.each do |c| %>
<%= c.username %>
<br>
<%= c.text %>
<% end %>
<%= form_for #comment, :url => thing_path do |f| %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :comment %>
<%= f.text_field :text %>
<%= f.submit "Enter", class: "btn btn-small btn-primary" %>
<% end %>
</div>
</div>
</div>
THINGS CONTROLLER
class ThingsController < ApplicationController
def show
#thing = Thing.find(params[:id])
#thing.comments.build
#comment = Comment.new
end
def index
end
def new
#thing = Thing.new
#things = Thing.all
end
def create
#thing = Thing.new(thing_params)
if #thing.save
redirect_to #thing
else
render 'new'
end
end
private
def thing_params
params.require(:thing).permit(:name, :avatar)
end
end
COMMENTS CONTROLLER (I put asterisks around the line where the error is)
class CommentsController < ApplicationController
def show
#comment = Comment.find(params[:id])
end
def new
#comment = Comment.new
#comments = Comment.all
end
def create
****#thing = Thing.find(params[:thing_id])****
#comment = #thing.comments.create(comment_params)
redirect_to thing_path(#thing)
end
end
private
def comment_params
params.require(:comment).permit(:user, :text, :upvotes, :downvotes, :thing_id)
end
end
ROUTES
Website::Application.routes.draw do
get "comments/new"
get "comments/show"
get "things/new"
root 'home_page#home'
get "all/things/new" => 'things#new'
get "all/allthings"
resources :things
resources :good_comments
get "things/show"
get "things/results"
end
You are posting the #comment form to post '/things' path.
<%= form_for #comment, :url => thing_path do |f| %>
It should just be <%= form_for #comment do %> (Rails is smart enough to plug in the comments_path) or if you feel like being more explicit (even though it's not necessary)
<%= form_for #comment, url: :comments_path do %>
Another note though, if you want that Comment to be tied to that specific Thing then in your models it should be
Class Thing
has_many :comments
end
Class Comment
belongs_to :thing
end
Then make sure in your database comment has a thing_id foreign_key field and then your form for comment should actually look like
<%= form_for #thing, #comment do %>
<% end %>

Resources