Rails ajax error while creating - ruby-on-rails

Hello guys I want use ajax in my rails application :
Here is my routes.rb file
ExampleAjax::Application.routes.draw do
root 'users#index'
resources :users
end
my controller file
class UsersController < ApplicationController
def index
#users = User.all
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.js {}
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:fname)
end
end
My view files
index.html.erb
<b>Users</b>
<ul id="users">
<% #users.each do |user| %>
<%= render user %>
<% end %>
</ul>
<br>
<%= form_for(#user, remote: true) do |f| %>
<%= f.label :fname %><br>
<%= f.text_field :fname %>
<%= f.submit %>
<% end %>
new.html.erb
<%=form_for(#user, remote: true) do |f|%>
<p>
<%= f.label :fname %><br>
<%= f.text_field :fname %>
</p>
<p>
<%= f.label :lname %><br>
<%= f.text_field :lname %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
_user.html.erb
<li><%= user.fname %></li>
_create.js.erb
$("<%= escape_javascript(render #user) %>").appendTo("#users");
And my problem is when I click create user
I got the following error in console
POST http://localhost:3000/users 500 (Internal Server Error)

Your code is hitting this block:
format.js {}
Which has nothing defined in it, so your app will try to do what it normally does, ie. render the view for the action you are in.
You are in a create action, and your format is js, so it will try to render create.js.erb.
You should rename your _create.js.erb to remove the underscore.

Ajax
I want use ajax in my rails application
To give you some info about Ajax, it's basically integrated in your application already:
Ajax is a group of interrelated web development techniques used on the
client-side to create asynchronous web applications
It's basically a way to send an asynchronous request to your web app (through javascript). Asynchronous essentially means you're sending requests out of scope of the typical HTTP "synchronous" request structure
HTTP works by responding to requests. Each click you perform is sending a request to your server, which responds with data. Synchronous requests are ones you perform in order, whereas asynchronous "ajax" ones are sent independently
Code
Your problem is you don't have a create.js.erb file:
respond_to do |format|
format.html #-> action.html.erb
format.js #-> action.js.erb
end
Unless you call some other methods in this block (such as render nothing), Rails will look for your action.js.erb file in your views directory
Rails
Rails handles all requests equally, and determines if it's an ajax request using the ActionDispatch::Http::MimeNegotiation class
This means you don't have to do anything "special" to use Ajax -- just send the requests to your routes, and handle them in the backend using respond_to do |format|

Related

Rails form_with errors (remote: true)

How can I display errors using Rails form_with (remote form with Ajax) helper?
I have this code:
def create
#incoming_package = IncomingPackage.new(tracking: params[:tracking])
if #incoming_package.save
redirect_to admin_incoming_packages_path, notice: "created"
else
flash.now[:danger] = "error" # not displayed
end
end
Here is my form:
<%= form_with url: admin_incoming_packages_path do |form| %>
<%= form.text_field :tracking, required: true, autofocus: true, autocomplete: :off %>
<%= form.submit "Add" %>
<% end %>
If there is no errors rails-ujs + Turbolinks works fine and new package is automatically added on page.
How can I display errors (or anything) if a package failed to save?
Here's a simple way to get you started:
On your form's view page:
<% if #incoming_package.errors.any?
<ul>
<% #incoming_package.errors.each do |error| %>
<li><%=error.full_messages%></li>
<% end %>
</ul>
<% end %>
Then on your create action do:
def create
#incoming_package = IncomingPackage.new(tracking: params[:tracking])
respond_to do |format|
if #incoming_package.save
flash[:success] = "The package was saved."
format.html { redirect_to admin_incoming_packages_path, notice: "created" }
format.json { render json: {success: true}
else
#errors = #incoming_package.errors.add(:base, "Some custom message here if you like")
flash.now[:danger] = "error" # not displayed
format.html { render 'new' }
format.json { render json: #incoming_package.errors, status: :unprocessable_entity }
end
end
end
You must also make sure your new action has:
#incoming_package = IncomingPackage.new
If you want to check any errors ruby give a very easy way to do it
#incoming_packages.errors.full_messages will show all errors related to your model. also you can interact with all these errors
`<%if #incoming_packages.errors.any?%>
<% #incoming_packages.errors.full_messages.each do |message| %>
<%= message %>
<%end%>
<%end%>`

Form hidden fields and security

I m using hidden field in my app to add user_id to my database "Camping". I have associations "User" has many campings and "Camping" belongs_to "user".
When I run firebug or something like this, I can modify user_id value of this field. If any user puts his ID, I can modify object to other user... I want to avoid this !
My code
<%= f.hidden_field :user_id, :value => current_user.id %>
This code, is necessary because I allow only user to edit / updated / create object if they have user_id == current_user.id.
How to fix this security problem ?
By the way, I m using devise.
Edit with full code
My _form.html.erb
<%= form_for(camping) do |f| %>
<% if camping.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(camping.errors.count, "error") %> prohibited this camping from being saved:</h2>
<ul>
<% camping.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="form-group">
<label for="name">Nom du camping</label>
<%= f.text_field :name, autofocus: true, class:"form-control", id:"name", :required => true%>
</div>
<div class="actions">
<%= f.submit "Enregistrer", class:"btn btn-success" %>
</div>
<% end %>
my controller
def new
#camping = Camping.new
#campings = Camping.all
end
def edit
end
def create
#camping = Camping.new(camping_params)
respond_to do |format|
if #camping.save
format.html { redirect_to #camping, notice: 'Camping was successfully created.' }
format.json { render :show, status: :created, location: #camping }
else
format.html { render :new }
format.json { render json: #camping.errors, status: :unprocessable_entity }
end
end
end
def update
#camping = Camping.find(params[:id])
respond_to do |format|
if #camping.update(camping_params)
format.html { redirect_to #camping, notice: 'Camping was successfully updated.' }
format.json { render :show, status: :ok, location: #camping }
else
format.html { render :edit }
format.json { render json: #camping.errors, status: :unprocessable_entity }
end
end
end
my edit.html.erb
<div class="containershow">
<h1>Editing Camping</h1>
<%= render 'form', camping: #camping %>
<%= link_to 'Show', #camping %> |
<%= link_to 'Back', campings_path %>
</div>
my new.html.erb
<h1>New Camping</h1>
<%= render 'form', camping: #camping %>
<%= link_to 'Back', campings_path %>
Edit solution ?
User can create and update his camping. I delete hidden_field
def create
# #camping = Camping.new(camping_params)
#camping = Camping.new((camping_params).merge(:user_id => current_user.id))
respond_to do |format|
if #camping.save
format.html { redirect_to #camping, notice: 'Camping was successfully created.' }
format.json { render :show, status: :created, location: #camping }
else
format.html { render :new }
format.json { render json: #camping.errors, status: :unprocessable_entity }
end
end
end
In Devise, the current user object is in current_user, available to your controllers. When saving the model, make sure to fill the user id field from that object, and not user input in the update action of your controller. Note that the edit action does not matter, that just renders the edit page, the actual update happens in update (if you follow the default conventions). Of course if you don't want users to even see other users' objects, you also need access control in other controller actions like edit as well, but that (implementing access control in a multi-tenant Rails application) is a different and much broader question.
More generally, be aware that anything that comes from a request can very easily be forged by a user. Always implement security server-side and do not trust user input!
Edit (seeing your code)
To prevent users updating others' Campings, you need to check in update after getting the #camping object (the second line) whether that's a camping object that your logged on user (current_user.id) is supposed to be able to edit.
The same way, if you want to prevent users from creating Campings for other users, you need to make sure in create that user_id will be set to the current user, something like #camping.user_id=current_user.id.
Similarly, if you want to prevent having a look at each other's Campings, you need to add checks to edit, show and pretty much all actions that return such objects.
There are gems like cancan and cancancan that may help with access control in Rails, they are worth a look!
Your Question is quite interesting but simple In the any HTML View Any one can change anything this will cause a security wise vulnerability as well.
To avoid these issues we need to authenticate it by two way You have to check the code by like It should be use by Controller not by view.
Suppose If you are creating any article of particular user
So To avoid it what you can do You can set the User ID in Session and make a Helper Method to find Current User always
So that you can find current user directly from controller and create article according to user
def Create
#article = current_user.articles.create(article_params)
end
This kind of Two way checking you can put up so that It will be safe.
To avoid the spend time on these work you can use gem directly like Devise

Rails: ActionController::InvalidAuthenticityToken when adding a Image

I am new to Ruby-on-rails and I am currently working on a project that let a user log in to add,create update delete a Marvel character. Each characters have a name, description, origin, alliance and image.
I used Carrierwave for file upload.
I used the scaffold command and everything was working fine, until I decided to be able to create and update my characters on the same page using .js.erb files instead of having to redirect the user to 2 different pages for the create and the update.
I have the following error everytime I try to create a character with a image. everything works fine when I don't add a image:
ActionController::InvalidAuthenticityToken
I know that there are a few different other similar questions already asked on the forum but I can't seem to find the answer to my problem.
I am using Rails 4.2.6.
I tried to add the gem remotipart but it didn't fix my issue.
create.js.erb code:
$("#characters").append("<%= escape_javascript(render #character)%>");
create action in the controller:
def create
#character = Character.new(character_params)
respond_to do |format|
if #character.save
format.html { redirect_to #character, notice: 'Character was successfully created.' }
format.json { render :show, status: :created, location: #character }
format.js
else
format.html { render :new }
format.json { render json: #character.errors, status: :unprocessable_entity }
end
end
end
I hope I provide enough information, thanks in advance!
Edit:
Here is the code I have in the form.html.erb that let the users add a image:
<div class="field">
<%= f.label :image %>
<%= f.file_field :image %>
<% if f.object.image %>
<%= image_tag f.object.image.url %>
<!--<%= f.label :remove_image %>
<%= f.check_box :remove_image %> -->
<% end %>
</div>
I think your Rails forms now will not render the CSRF field in the form:
<%= form_for #character, :remote => true, :authenticity_token => true,:multipart => true do |f| %>
.....
<% end %>
skip_before_action :verify_authenticity_token
Put this in your controller

Rendering a partial from one controller to another below content

In my views, I have comments/_form.html.erb, and there is another controller views for post posts/show.html. I want to render comments/_form.html.erb in posts/show.html, which shows an individual post and comments associated with that post, and it is all set and working fine.
I want to provide ability to comment and render that partial below these comments so that we can make new comment on the same posts/show.html page instead of navigating to comments/new.html.erb page. I am using nested resources like:
resources :posts do
resources :comments
end
In my comments/new.html.erb, I am doing this:
<%= form_for([:post, #comment]) do |f| %>
....
<% end %>
How should I render it in my posts/show.html.erb page?
Javascript is the missing piece in your puzzle. Essentially you'll do 3 things.
Make sure your form is using js to submit (remote)
Make sure your controller responds to js input
Create a js.erb file that will append each new comment
Implementation notes:
I would probably do something like this:
Add the form to the view, and add an element that wraps around the comments, in this case, I used ul#comments
# app/views/posts/show.html.erb
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Body:</strong>
<%= #post.body %>
</p>
<br/>
<ul id="comments">
<%= render #comments %>
</ul>
<%= form_for [#post, #new_comment], remote: true do |f| %>
<%= f.text_field :body %>
<%= f.submit %>
<%end%>
Add the js response in the controller
# app/controllers/comments_controller.rb
def create
#post = Post.find params[:post_id]
#comment = #post.comments.new(comment_params)
#new_comment = #post.comments.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to [#post, #comment], notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
format.js
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
Then add a ujs file to make your changes on the fly (this does 2 things, adds a new comment and empties the form).
# app/views/comments/create.js.erb
$('#comments').append("<%= escape_javascript(render partial: '/comments/comment', locals: { comment: #comment } ) %>");
$('form.new_comment').find("input#comment_body").val('');
Also to note::
I'm using #new_comment so there is no interference when you render a newly created comment
You'll need to add #new_comment in 2 places, first in your posts show action and also in your comments create action

get value from form_for

I'm using rails 4.0.1
<%= form_for #event, :html => { :multipart => true} do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :content %><br>
<%= f.text_area :content %>
</div>
<div class="field">
<%= f.label :place_id %><br>
<%= f.collection_select(:place_id, #places, :id, :title) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And I want to check for current_user.id and Place.user_id (it stores creator id). In Events cotroller i'm trying to use:
def create
#places = Place.all
#event = Event.new(event_params)
#event.user_id = current_user.id
#curplace = Place.find_by(id: params[:place_id])
#event.content = #curplace.id
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render action: 'show', status: :created, location: #event }
else
format.html { render action: 'new' }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
But i got an error. I think i'm not getting this Place_id param right or anything else?
Further to the comment from Ankush Kataria, the form_for helper basically creates a form which combines all the params into a hash, as opposed to form_tag, which just makes the params independently
As you've discovered, this means your params will be accessed by:
#form_for
params[:variable][:param]
#form_tag
params[:param]
form_for
The reason why this is important is because if you're using the RESTful routes interface, you'll be able to create / edit / update a variety of records
form_for basically keeps consistency throughout this process, pre-populating your forms with the various values, and keeping your code DRY
To call a form_for helper, you have to define the #varaible the form will populate. This #variable needs to be an ActiveRecord object, and is why you have to build it in the new action before your form shows
form_tag
form_tag is much more independent of the form_for helper, doesn't require any #variable, and creates the params individually
You'd use a form_tag for the likes of a contact us form or similar
Your Code
Your form looks good, but your create action can be dried up:
def create
#places = Place.all
#event = Event.new(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render action: 'show', status: :created, location: #event }
else
format.html { render action: 'new' }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
private
def event_params
params.require(:event).permit(:title, :content).merge(user_id: current_user.id, place_id: params[:event][:place_id])
end
You are right that params[:place_id] isn't returning the value you expect. It only returns nil. To get the :place_id that's submitted by the form, you have to do this:
#curplace = Place.find(params[:event][:place_id])
Just replace the old line with the code above. It's because your form submits the data in the fields inside an :event key in the params hash since you're using the form_for helper method provided by Rails. That is its default behavior unless you change the 'name' attribute's value in the input fields.
Hope that helps!

Resources