Rails: how to communicate view controller in AJAX? - ruby-on-rails

The case is when user click an add link, if the url already added, there will be a alert otherwise will display a form to add new bookmark. The code below works quite well for checking the duplicated url, but if the url is not duplicated I just don't know how to render a add bookmark (in this case the page will be loaded like a normal non ajax request)
This is the link in view
<%= link_to "add", user_bookmark_add_path(current_user, bookmark), remote: true %>
The link will invoke the controller action add
# controllers/bookmarks_controller.rb
def add
#bookmark = Bookmark.find(params[:bookmark_id])
respond_to do |format|
format.js
end
end
The javascript file
# views/bookmarks/add.js.erb
<% if duplicated_url? #bookmark.url %>
alert("Duplicated")
<% else %>
# how to render the new bookmark form here
<% end %>
Any suggestion ? Thanks

Create a partial for new bookmark form.
_form.html.erb
<%= form_for(bookmark) do |f| %>
<%= f.text_field :name %>
<%= f.submit "submit" %>
<% end %>
Add id to your link
.html.erb
<%= link_to "add", user_bookmark_add_path(current_user, bookmark), remote: true, id: "bookmark" %>
Replace your link with partial.
.js.erb
<% if duplicated_url? #bookmark.url %>
alert("Duplicated")
<% else %>
$("#bookmark").replaceWith("<%= j render "form", bookmark: Bookmark.new %>");
<% end %>

On your add.js.erb file, in the else part of the code you can append a partial to your list like this:
$('#your_list').append(
"<%= escape_javascript(render('your_item_of_the_table_partial')) %>"
);
This partial can be a list item, a table row, a div with your content, anything. The thing is, you will need a chunk of html to be re-rendered on your screen with the new content.
Example of a list item partial:
# _bookmark_item.html.erb
<li><%= #bookmark.url %> </li>

Try something like this:
$('#your_div_id').append('<%= escape_javascript(raw render :partial => 'your_form_partial') %>')
This will add the contents of your ruby partial to the DOM.

Related

Ruby on Rails if/unless statment for AJAX destroy when cart is empty

I am building webstore. I added a bit of AJAX functionality to add, update and remove items from my cart without refreshing.
It works perfect as long as there are no items in a cart and render cart_empty partial properly.
The problem is when I add few items, and I can update/remove them without refreshing and
finally I remove the last one, and it do not switch to the cart_empty partial and there are only empty table headers left from cart-items partial.
Can I add some logic to destroy.js.erb?
destroy.js.erb
$("#cart-item").html("<%= j render 'carts/cart_items' %>");
the show.html.erb contains this unless function:
<% unless current_order.order_items.empty? %>
<div id="cart-item">
<%= render 'cart_items' %>
</div>
<% else %>
<div id="cart-empty">
<%= render 'cart_empty' %>
</div>
<% end %>
Maybe should I modify somehow my controller to check if there are order_items in a current_order?
Thank you!
A JS.erb template is evaluated in exactly the same way as a HTML template. So you can just add a condition:
<% if current_order.order_items.any? %>
$("#cart-item").html("<%= j render 'carts/cart_items' %>");
<% else %>
$("#cart-item").html("<%= j render 'carts/cart_empty' %>");
<% end %>
None that this implies that current_order is either a helper or a local passes to the view.
But you might want to refactor this and push the condition down to the partial:
# carts/cart_items.html.erb
<% if cart_items.none? %>
<% render :cart_empty %>
<% else %>
# ...
<% end %>
Which will let you just write:
<%= render 'carts/cart_items', cart_items: current_order.order_items %>
See:
Layouts and Rendering in Rails - passing local variables

Try to modify the "Todo app"

I'm starting on ruby on rails, first thing I want to try is modifying the "Todo app" example.
I do this by the tutorial: https://www.youtube.com/watch?v=fd1Vn-Wvy2w
After I finished, I saw that when I clicked on a todo_list, it will redirect to "show" form todo_list, but now I want the "show" display on the index with all the todo_list. I have tried to write
<%= todo_items.content %>
on the index page but it got some errors. Is there any solution or should I modify something on the Controller page so that
todo_items.content
should be able to display on the Index page
You need to load those items in your controller action first:
def index
#todo_items = TodoItem.all
end
then in index.html or whatever template you are rendering for this action you can render this collection:
<%= render #todo_items %>
that should render an todo_item partial that you should have created based on your video located at /app/views/todo_items/_todo_item.html.erb. Or you can do:
<% #todo_items.each do |item| %>
<%= item.content %>
<% end %>
In controller:
def index
#todo_lists = TodoList.all
end
in view:
<% #todo_lists.each_with_index do |list, index| %>
List <%= index + 1 %> todos:
<%= render list.todo_items %>
<% end %>

check if Rails partial is empty

I have a main page that is responsible for HTML/CSS styling, but some of the contents come from partials. A partial receives some locals or params, i.e. current_user or person, and displays information if any.
Is there a way for me to check if a partial rendered anything? My end goal is something like this:
<% if my_partial can render something %>
<div class="css_for_something">
<%= render(partial: 'my_partial', locals: {...} ) %>
<% else %>
<div class="css_for_no_info">
<%= render something else %>
<% end %>
I do not want the partials to handle styling logic; they just need to display content if any. Conversely, the main page should not know anything about the logic in the partial(s), such as checking values or querying the database.
Thank you
Unfortunately, Chris Peter's solution did not work for me on rails 4.2.4, as render_to_string seems to not be available in views.
However, the following worked (rails 4.2.4):
<% partial_content = render partial: 'my_partial' %>
<% if partial_content.present? %>
<%= partial_content %>
<% else %>
<%# rendered if partial is empty %>
<% end %>
Be aware that the present? check really only checks if what was rendered is empty. If, something, e.g. a HTML comment, is returned, the check returns false.
Try storing the value generated by render_to_string in a variable:
<% partial_content = render_to_string(partial: 'my_partial', locals: {...} ).strip %>
Then you can see if it contains any content:
<% if partial_content.present? %>
<%= partial_content %>
<% else %>
<div class="css_for_no_info">
<%= render something else %>
</div>
<% end %>

Render to partial by Ajax in Rails App

I have almost done! but I have an issue, in my Controller file have this:
def show
#user = User.find(params[:id])
#posts = #user.posts.paginate(page: params[:page])
end
Then I have this piece of code in my file show.html.erb:
<div class="span8">
<%= render 'follow_form' if signed_in? %>
<% if #user.posts.any? %>
<h3>Microposts (<%= #user.posts.count %>)</h3>
<div id='posts'>
<div class='page'>
<ol class="microposts">
<%= render #posts %>
</ol>
</div>
</div>
<% end %>
</div>
At the bottom of this file, I have a Javascript code that I have taken from the tutorial: https://github.com/amatsuda/kaminari/wiki/How-To:-Create-Infinite-Scrolling-with-jQuery
In the same folder I have the file index.js.erb with:
$("#articles").append("<div class='page'><%= escape_javascript(render(#users)) %></div>");
$("#posts").append("<div class='page'><%= escape_javascript(render(#posts)) %></div>");
In a partial _posts.html.erb have this:
<div class='article'>
<%= image_tag(user.picture_url, :width => 50) %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</div>
The first one already works in my file index.html.erb, the problem is with the second piece of code, when I try to render the partial at #post, It brings the follow log:
**
'nil' is not an ActiveModel-compatible object that returns a valid partial path.
Extracted source (around line #2):
1: $("#articles").append("<div class='page'><%= escape_javascript(render(#users)) %></div>");
2: $("#posts").append("<div class='page'><%= escape_javascript(render(#posts)) %></div>");
**
How can I render that partial?
Thanks a lot :D
I usually use the .js.erb template to render the partial into a var then set it on the page using JS. Be sure to escape_javascript the template content otherwise you will get JS errors.
<% template_html = render :partial => '_feed_item.html.erb' %>
<%="$('div#content').html('#{escape_javascript(template_html)}</div>');" %>
I think the above should work in erb. I use HAML so mine looks like:
-template_html = render :partial => 'partial_template'
!="$('div#content').html('#{escape_javascript(template_html)');"
Cheers.
Based on your In script I'm calling to /users?page=, and I was wondering that It may calls the line, you must make sure that your controller is populating the #posts variable if your view is using this. Can you show the controller method users?

ruby on rails render deosn't find the file

I'm new to ruby on rails.
In views/events I have "_form.html.erb" which is rendered in "new.html.erb" by this code:
<%= render "form" %>
Now I want to render "_form.html.erb" in "index.html.erb" which is in the same folder(views/events).
But I get the error "missing template".
I guess I have to add some thing to controller, please help me to render form in other pages of views...
You "usually" don't render a form in an index action. Most form partials are setup semantically to expect a #my_resource, but if you're doing everything the rails way you're not going to have a instance variable during your index action. There's a number of ways you can do this but this is probably the quickest.
You probably have some collection (let's pretend you're using books) in your index action:
#views/books/index.html.erb
<% #books.each do |book| %>
...
<%= render "form" %>
...
<% end %>
You can just set an instance variable somewhere prior to rendering the form:
#views/books/index.html.erb
<% #books.each do |book| %>
<% #book = book %>
...
<%= render "form" %>
...
<% end %>
Another way to do it would be through passing in some locals to a partial. You'd have to change all of your references in _form to use a local variable instead. Then you can call render like this:
<%= render :partial => "form", :locals => {:book => book } %>
You can try
<%= render "events/form" %>
I had this problem before and this solved

Resources