I would like to use Ajax to add a micropost to my home page without redirect as soon as it is created. I added remote: true in the form:
<%= form_for(#micropost, html: { multipart: true }, remote: true) do |f| %>
and edited the create action of the microposts controller as follows:
def create
#micropost = current_user.microposts.build(micropost_params)
microposts_number = current_user.microposts.where("created_at >= ?", Time.zone.now.beginning_of_day).count
if microposts_number < 10
if #micropost.save
respond_to do |format|
format.html do
flash[:success] = "Micropost created!"
redirect_to root_url
end
format.js
end
else
#feed_items = []
flash[:danger] = #micropost.errors.full_messages.join(', ')
render 'static_pages/home'
end
else
flash[:danger] = "You have exceeded your daily share of microposts (10)."
redirect_to root_url
end
end
The microposts are shown in the home page as orded list of items, where #feed_items is a collection of microposts for current_user, thus belonging to Micropost:
<% if #feed_items.any? %>
<ol class="microposts">
<%= render #feed_items %>
</ol>
<%= will_paginate #feed_items %>
<% end %>
Therefore I created app/views/microposts/create.js.erb, using jQuery to select ol.microposts and function prepend() to add the newly created micropost to the page:
$("ol.microposts").prepend('<%= escape_javascript(render partial: #micropost) %>');
The partial _micropost.html.erb, used to build the li elements inside ol.microposts is (simplified) below:
<li id="micropost-<%= micropost.id %>">
<%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
<span class="content">
<%= micropost.content %>
<%= image_tag micropost.picture.url if micropost.picture? %>
</span>
</li>
However the Micropost controller does not respond to the Ajax request but redirect to root_url, responding only to html (output from cloud9 server):
Started POST "/microposts" for 82.56.61.198 at 2017-07-14 09:44:55 +0000
Cannot render console from 82.56.61.198! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by MicropostsController#create as HTML
...
Started GET "/" for 82.56.61.198 at 2017-07-14 08:51:42 +0000
Cannot render console from 82.56.61.198! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by StaticPagesController#home as HTML
I do not understand why the create action of the Micropost controller does not respond to js format. I tried to clone partial _micropost.html.erb and use the instance variable #micropost instead of the variable micropost of the iteration, but it did not work. There are no errors in the server log.
Processing by MicropostsController#create as HTML
It is due to the limitation of AJAX. From the Reference
Ajax uses something called an xmlhttprequest to send your data.
Unfortunately, xmlhttprequests cannot post files
That said, you cannot post files via AJAX. You may need some help with Remotipart or Jquery-File-Upload
You only told the action to respond_to with format.js in your successful save path. You'll need to add a respond_to block with whatever you want to do for your js everywhere you render or redirect_to
Related
Trying to get a flash message and render a partial on an ajax call with link_to and remote:true
I have in my controller examples.rb:
def create
* Some stuff happens *
respond_to do |format|
format.js
format.html do
flash[:notice] = "Works!"
redirect_back(fallback_location: root_path)
end
end
end
I have the "link_to" form in _one_partial.html.erb
<%= link_to examples_path(whatever: locals[:whatever]), class: "whatever", method: :post, remote: true do %>
<div class="whatever_vix">
<p> Click Here! </p>
</div>
<% end %>
which is in a view as:
<div id="addhere">
<%= render 'favorites/one_partial', locals: {whatever: #whatever} %>
</div>
and in create.js.erb
$('#addhere').append("<%= j render 'whatever/another_partial' %>")
The ** some stuff happens ** part in my controller obviously works, but the new partial in create.js.erb doesn't show, neither the flash message appears once I add remote:true to the "link_to" form
When calling render The view is not being updated, however, I do notice in the network tab, after the POST request is made to me POST route, it's returning HTML as the response, and the response has my rendered error message. It's just not updating the page. I don't know what to make of that.
In my POST action, I'm forcing this to be called
flash.now[:notice] = responseMessage
render :deactivate_show
Which renders the action:
def deactivate_show
#user = User.find(params[:id])
authorize! :deactivate_user, #user
if current_user.role == "admin"
if #user.broker?
#companyUsers = User.where(parent_id: #user.id)
#properties = Property.where(user_id: #user.id)
.or(Property.where(user_id: #companyUsers.ids))
elsif #user.broker_manager?
# get all agents in company
# exclude current user
# get broker
#companyUsers = User.where(parent_id: #user.parent_id)
.where.not(id: #user.id)
.or(User.where(id: #user.parent_id))
#properties = Property.where(user_id: #companyUsers.ids)
.or(Property.where(user_id: #user.parent_id))
else #user.agent?
#properties = #user.properties
if #user.parent_id?
#companyUsers = User.where(parent_id: #user.parent_id)
.where.not(id: #user.id)
.or(User.where(id: #user.parent_id) )
else
# dealing with owner.
#companyUsers = User.where('role IN (2,4,1)')
.where.not(id: #user.id)
end
end
else
end
end
which renders a view I have that displays the form.
I added to my show view:
<div class="messages">
<% flash.each do |key, value| %>
<div class="hello"><%= value %></div>
<% end %>
</div>
Note the class of "hello".
When I make a POST request, the response in the network tab has the notice:
Rendered from POST request response:
<div class="messages">
<div class="hello">testing errors</div>
</div>
Edit: here's the form:
<div class="form-wrap">
<%= form_with do %>
<%= button_tag( id: 'button--submit', class: 'button button--secondary') do %>
<i class="icon-arrow-right"></i>
<span>Deactivate</span>
<% end %>
<% end %>
</div>
Well the actual answer was something no one could have provided since I didn't share my form. I was using form_with, which apparently does AJAX by default, thus not rendering the view.
Thanks for the help from this question: Rails render not showing in browser, despite positive server reply
I've changed
<%= form_with do %>
to
<%= form_with local: true do %>
and now it works.
The Flash is only rendered upon a new request, which you don't make with render. Instead, you should use flash.now[:notice] to have it display on render.
I realize there are dozens of similar questions here on this topic, I have looked through many of them and tried to duplicate the solutions and nothing has worked for me.
I have a list of tasks displayed in the index view as a partial, when the user adds a task I would like list to show the newest task (as well as all the others already there).
Here is the create controller:
def create
#task = current_user.tasks.build(task_params)
if #task.save
flash[:success] = "Task added"
respond_to do |format|
format.js
end
else
flash[:error] = "Task not added"
render 'new'
end
The _new partial:
<%= form_for(#task, method: :post, remote: true) do |f| %>
<%= f.label :comments %>
<%= f.text_field :comments, id: "task-comments" %>
<%= f.submit "Insert" %>
<% end %>
Index.html.erb
<div id="new-task-form">
<%= render 'new' %>
</div>
<div id="current-tasks">
<%= render partial: 'show_list', locals: {tasks: #tasks} %>
</div>
create.js.erb
console.log("create.js.erb called");
document.getElementById("task-comments").value = "";
document.getElementById("current-tasks").html('<%= j(render partial: "show_list") %>');
I have been able to get the console to log the message and even been able to clear the input box but the partial does not render, I have tried this in a few different ways and the script always seems to stop executing when it gets to the escape javascript line.
There are no JS errors, as stated above, the console logs the message when the "submit" button is pressed. There is a warning [Violation] Forced reflow while executing JavaScript took 114ms but I don't think that is relevant to this issue.
Here is the partial that I am trying to render _show_list.html.erb
<% unless #tasks.nil? %>
<ul>
<% tasks.each do |tsk| %>
<li><%= tsk.comments %></li>
<% end %>
</ul>
<% end %>
def create
#task = current_user.tasks.build(task_params)
if #task.save
flash[:success] = "Task added"
#respond_to do |format|
#format.js
#end
else
flash[:error] = "Task not added"
render 'new'
end
end
It's always good practice to use local variable in partial
1) => Index.html.erb
<div id="new-task-form">
<%= render 'new' %>
</div>
<div id="current-tasks">
<%= render partial: 'show_list', locals: {tasks: #tasks} %>
</div>
2) => If you are using jquery (create.js.erb)
console.log("create.js.erb called");
$("#task-comments").val('');
$("#current-tasks").html('<%= j render "show_list", tasks: #tasks) %>');
3) => _show_list.html.erb(Use tasks instead of #tasks)
<% unless tasks.blank? %>
<ul>
<% tasks.each do |tsk| %>
<li><%= tsk.comments %></li>
<% end %>
</ul>
<% end %>
ok you have some problem here with your validation on the show_list partial.
you have this line
<% unless #tasks.nil? %>
try to use something more readable like
<% if #tasks.present? %>
and on your controller create action, you don't fill the #tasks variable, so that's the problem in reality, add on you controller the load for all the tasks after saving the new one.
if #task.save
#tasks = Task.all
flash[:success] = "Task added"
and that will make it work, but I recommend to load just the created one and add just one column to the table and not update the complete list again if you have all the others on the client already.
Getting trouble with known at the title.
I have two forms in new.html.erb view. One is form_for, other one is form_tag, both as partials.
form_for is to save some data to models.
form_tag is to do little action with params. and give back the processed data to partilal(js). here I'm stuck. this not working.
form_tag is not working. after submitting, the action "urlchanger" don't reflect any data to partial "urlchanged". in My plan, this should get #url, but get errors (detail below).
This is the error respowned by submitting form_tag.
ActionController::RoutingError: No route matches [POST] "/notes/new"
..
Processing by Rambulance::ExceptionsApp#not_found as JS
Parameters: {"utf8"=>"✓", "url"=>"<iframe src=\"http://hogehoge.com/hoge" frameborder=0 width=510 height=400 scrolling=no></iframe>", "urlchanger"=>"変換"}
Rendered errors/not_found.json.jbuilder (0.2ms)
Completed 404 Not Found in 66ms (Views: 48.1ms | ActiveRecord: 0.0ms)
as the non partial. everything works fine.
but, I want them to work in single view.
notes
--new.html.erb
----_form.html.erb
----_urlchanger.html.erb
----_urlchanged.js
----_urlchanger.js.erb
!-------------notes/new.html.erb-------------!
<%= render 'form' %>
<%= render 'urlchanger' %>
!-------------notes/_urlchanger.html.erb-------------!
<%= bootstrap_form_tag(controller: "notes", action: "urlchanger", remote: true ) do |f| %>
<%= f.text_field :url, hide_label: true, :class => "form-control", placeholder: "ペーストエリア" %>
<%= f.submit "変換", data: { disable_with: '送信中'} %>
<div id="urlchanged" >
<%= render "urlchanged" %>
</div>
<% end %>
!-------------notes/_urlchanged.html.erb-------------!
<input type="text" class="form-control" value="<%= #url %>">
!-------------notes/_urlchanger.js.erb-------------!
$('#urlchanged').html('<%= j(render("urlchanged")) %>');
!-------------routes-------------!
resources :notes do
collection do
post :create
post :urlchanger
end
end
!-------------Notes controller-------------!
def urlchanger
url = params[:url]
if /(https?:\/\/\D*\w*)/ =~ url
#url = $&
end
end
Please help. Thank you.
What happens when you change your notes/_urlchanger.js.erb to notes/urlchanger.js.erb?
OR try this
def urlchanger
url = params[:url]
if /(https?:\/\/\D*\w*)/ =~ url
#url = $&
end
respond_to do |format|
# format.html { redirect_to(:back) } # no idea what you might want to do here
format.js { render partial: "notes/urlchanger" }
end
end
solved problem!!
I don't know why it works ('A')
But like the code blow works good.
---------------Note.controller----------------------
def urlchanger
url = params[:url]
if /(https?:\/\/\D*\w*)/ =~ url
#url = $&
end
respond_to do |format|
# format.html { redirect_to(:back) } # no idea what you might want to do here
format.js
end
end
------------------notes/_urlchanger.html.erb-------------------
<%= bootstrap_form_tag( url: notes_urlchanger_path, remote: true ) do |f| %>
I cannot figure out why my rails views are not recognizing flash[:notice] or flash[:error]. I keep getting the following error regarding the partial view being rendered. The specific error is:
ActionView::Template::Error (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]):
In my controller I have
def index
#organisms = Organism.all
flash[:error] = "test"
flash[:notice] = "test"
respond_to do |format|
format.html
format.json { render :json => #organisms }
end
end
In my index.html.erb file I render out a partial through:
<%= render "shared/flash" %>
The partial has the following code.
<div id="flashes">
<% if flash[:notice] %>
<p id="flash_notice" class="messages notice"><%= flash[:notice] %></p>
<%= javascript_tag "$('#flash_notice').effect('highlight',{},1000);" %>
<% end %>
<% if flash[:error] || flash[:errors] %>
<p id="flash_errors" class="messages errors"><%= flash[:error] || flash[:errors] %></p>
<%= javascript_tag "$('#flash_errors').effect('highlight',{},1000);" %>
<% end %>
<% flash[:error] = flash[:errors] = flash[:notice] = nil %>
</div>
However, if instead of rendering the partial I throw in <%= notice %> it renders out the notice.
If I take the partial code and stick it in the top of the index.html.erb file it renders correctly. Thus, I assume that I am rendering the partial view wrongly?
Any help is much appreciated. Thanks!
Don't name your partial flash. Ruby on Rails creates a local variable with the same name as the partial. In your case, a flash local variable is being created.
Rename your partial to something other than flash and it should work.
Also, you shouldn't need to set flash to nil at the bottom of your partial. Let Rails take care of that for you.
You have to pass the flash to the partial:
<%= render 'shared/flash', flash: flash %>
Or a bit longer:
<%= render partial: 'shared/flash', locals: { flash: flash } %>