The problem is:
I need to render a collection of checkboxes via ajax, so I have this:
$("#imovel_tipo_imovel_id").on "change", ->
$.get("/admin/caracteristicas", { tipo_imovel_id: $(this).val() })
When I change a select value, it will hit my controller and render back a collection of checkboxes. The problem is that the partial I need to render must be inside a form and sent back to a different controller.
= simple_nested_form_for #imovel do |f|
.caracteristicas
= render 'my_partial', f: f
the partial
= f.simple_fields_for :caracteristicas_imovel do |c|
= c.collection_check_boxes :caracteristica_id_in, #caracteristicas, :id, :descricao
the js.erb responde:
$(".caracteristicas").html("<%= render 'my_partial' %>")
The controller:
def index
respond_to do |format|
format.js { #caracteristicas = Caracteristica.where(tipo_imovel_id: params[:tipo_imovel_id]) }
end
end
You see? So when I try to render my partial via ajax it complains that it has no f variable.
Am I doing this right? Is there a better way?
I would just use actual html here. Try rendering this page with the full code, inspecting it, and just copy/pasting the rendered html into your partial. I'm sure there's a way to hack it with helpers, but it just seems easier this way.
Related
So there are tons of articles about how to do this, but certainly there's a best practice...and I don't know enough to filter out silly solutions, good ones, and best ones.
I simply want to submit my forms via ajax (in a dialog) and get the errors back just like I would without using ajax...meaning I like the rails standard error handeling/flash messages/label classes.
Is the best way to reload the entire partial?
Is the best way to use .js.erb (or coffee) for partial stuff? (If so, can you explain how to use these partials?
Is the best way to parse JSON back into the form somehow?
What else am I missing in my [limited] knowledge base?
The way I'd do it is to render a create.js.erb view like:
$("#my_dialog").replaceWith("<%= j(render 'dialog') %>");
where _dialog.html.erb contains the HTML for the contents of your dialog.
<div id="my_dialog">
<!-- flash stuff etc -->
<%= form_for ... %>
<!-- ... -->
<% end %>
</div>
Your controller, for example, will look something like:
class EntriesController < ApplicationController
def create
#entry = Entry.new(params[:entry])
respond_to do |format|
if #entry.save
format.html { redirect_to #entry }
format.js {} # this will render create.js.erb for js requests
else
format.html { render action: "new" }
format.js {} # this will render create.js.erb for js requests
end
end
end
end
summit like 'dat. If you don't want to reload the whole form you can update or do whatever you want in .js.erb
Using js.erb is the way to go. Here's the rationale:
Reloading part of your page basically defeats the purpose of Ajax - which is to modify the page without having to reload or refresh anything. And parsing JSON would be quite tedious.
Using js.erb lets you easily leverage validations that Rails provides. In your js.erb, you can access anything that you normally would from your controller, including the validation errors, you and you can update DOM elements based on those errors. Since you're modifying individual DOM elements, you don't need to concern yourself over the fact that your form may be inside a partial.
In controller, I have #users_shown. In views, I render a partial _attendants.html.haml with #users_shown.
It's okay but there is a button on this page called attend_again, while you click this button, it will render the partial via AJAX with partial _attendants.html.haml.
The question is in the partial _attendants.html.haml, #users_shown is nil. I don't know why.
file _attendants.html.haml like this
- unless #users_shown.blank?
-#users_shown.each do |user|
user.name,user.id
You need to set #users_shown in your controller action that is rendering the ajax _attendants partial. It's a completely separate request, and needs all relevant data set appropriately.
Try add a local to the partial rendering like:
<%= render :partial => "xxxx/_page_attendants", :locals => { :users_shown => #users_shown } %>
I have a rails action called index that renders the content for my page along with the layout. When I go to the /index action with a browser it works like expected. I want to be able to also render this action by calling it with Ajax, I am doing this using the following:
<%= link_to "Back", orders_path, :id => 'back_btn', :remote => true %>
<%= javascript_tag do %>
jQuery("#back_btn").bind("ajax:complete", function(et, e){
jQuery("#mybox").html(e.responseText);
});
<% end %>
When the action is called this way I would like it to render and pass the index action back, excluding the layout. How can I do this?
You should be able to add a format.js action to your controller action like so:
respond_to do |format|
format.js
format.html
format.json { render json: #foos }
Ideally, you would want to create a index.js.erb file that would build the contents of the page:
$('#foos_list').update("<%= escape_javascript(render(#foos)) %>");
If you're going to update the contents of a div, to basically update a whole page inside of a layout, then you're going to want to change it up a little bit. Inside of the format.js, you can do this:
format.js { render 'foos/index', :layout => false }
But if you're trying to go with an ajaxified front-end, may I recommend a framework for doing this, like Spine? It will go a long way in helping you build your site.
Also, using a framework like this will force you to separate your application per #Zepplock's second suggestion.
You can just detect if the request is an XML HTTP Request, then render a blank layout like so:
render layout: 'blank' if request.xhr?
You'll need to create a blank layout in app/views/layouts/blank.html.erb like this:
<%= yield %>
You need a way to let server know that there's a difference in request type. It can be done in several different ways:
Append a key value to the URL (for example layout=off) and change your controller logic to render data with no view. This is kind of a hack.
Make your controller return data via XML or JSON (controller will know what content type is being requested) then format it accordingly and present in browser. This is more preferred way since you have a clear separation between content types and is better suited for MVC architecture.
Create an API that will serve data. This will lead to separate auth logic, more code on client side, additional APi controller(s) on server etc. Most likely an overkill for your case
I am trying to render a partial inside a JSON file so that I can use it via AJAX. Currently in my JSON file I have:
<% self.formats = ["html"]%>
{
"html": "<%= raw escape_javascript(render(:partial => 'shared/mini_posts', :locals => {:type => "left"}).to_json )%>"
}
This currently returns no response, but my logs show that shared/mini_posts was rendered.
Note that if I try something like:
{
"html" : "test"
}
This returns correctly.
My jQuery looks like:
$j.ajax({
url('/thepage.json'),
dataType: 'json',
success: function(data){
console.log(data);
}
})
In my case, I had the same problem for about a day and a half and after trying lots of combinations of escape_javascript, to_json, render ... content_type, etc I finally achieved what I was looking for, that is rendering a HTML partial in a json response.
So in your controller you have an action like
def index
#candidatos = Candidatos::Base.paginate(page: params[:page], per_page: 3).to_a
respond_to do |format|
format.html # index.html.erb
format.json # index.json.erb
end
end
and if the request had a .json it will use the index.json.erb template, and in my case that template is something like
<% self.formats = ["html"] %>
{
"html":<%= thumbnails_tag(#candidatos).to_json.html_safe %>
}
Note the self.formats = ["html"] is necessary because otherwise the "view" won't find the partial because it will look for a .json partial. and more important, don't use escape_javascript because it will fill the html with \t and \n. In other words, the idea is to pass the output of your partial to .to_json and then to .html_safe.
thumbnails_tag is just a helper I created because I'm using the partial in lots of parts of the app, but basically it has something like
def thumbnails_tag objs
#Uncomment the line below to test when no much data available
# #listas.fill(#listas.first, 0..6)
thumb_span = 4
case #candidatos.length
when 1..3
thumb_span = 12 / #candidatos.length
else
thumb_span = 4
end
thumbs = {span: thumb_span}
render partial: 'candidatos/thumbnails', locals: {candidatos: #candidatos, thumbnail_options: thumbs }
end
Finally, and just as an example, with this approach, in your .js assets you can do something like:
$.get('http://localhost:3000/candidatos.json?page=2', function(d){}, 'json')
.success(function(d){
$('#presidentes div.row-fluid .thumbnails').parent().append(d.html);
})
.error(function(event,error){
console.log(error);
})
No need to gsub for \t and \n in your rails view or JSON.parse string in your Javascript.
You need to change your controller. In the respond_to part you need to add json rendering. Like this:
respond_to do |format|
format.json { render :json => #instancevar }
....
...
..
end
Then you can simply add .json to your url and you will receive the data formated as json. What you might need to do is disabeling the JSON root hich is automaticly added by default. Just add this line to your environment (development.rb, production.rb,...) configuration:
config.active_record.include_root_in_json = false
This is important when you are parsing the json.
You can't call to_json on a partial... it's a method of ActiveRecord. If you want json there, then it should be inside the partial.
In my application.html.erb layout for my app, I want to have a partial that renders if it exists for the given view. for example.
If the visitor is at http://example.com/users/show, I'd want the partial /users/_sidebar.html.erb to render.
But if the visitor were at say, http://example.com/user/locations/san_francisco, I'd want the partial /users/locations/_sidebar.html.erb to render.
So the thing here is that if there were no partial for that controller/action it would render some generic partial in my shared directory, and I'd rather not litter every single view with content_for blocks ya know?
Any ideas guys?
My solution is a bit different. Throw this in your application helper:
def render_partial_if_exists(base_name, options={})
file_name = ::Rails.root.to_s+"/app/views/layouts/_#{base_name}.html.erb"
partial_name = "layouts/#{base_name}"
else_file_name = ::Rails.root.to_s+"/app/views/layouts/_#{options[:else]}.html.erb"
else_partial_name = "layouts/#{options[:else]}"
if File.exists?(file_name)
render :partial => partial_name
elsif (options.key?(:else) and !options[:else].nil? and File.exists?(else_file_name))
render :partial => else_partial_name
end
end
Then in your view:
<%= render_partial_if_exists "page_#{controller.action_name}_sidebar", :else => "page_sidebar" %>
In an edit action, if "layouts/page_edit_sidebar" exists it renders it, otherwise it will render a standby "layouts/page_sidebar"
Sean Behan has a great post on exactly this:
http://seanbehan.com/programming/render-partial-if-file-exists/
I might move it to a helper and tweak it a bit to:
<%= render_sidebar %>
# This method could use either the rescue or the if file exists technique.
def render_sidebar
render(:partial => "/#{controller.name}/sidebar"
rescue
#default side bar
end