Only show taxonomies that belong to the selected store model Ruby - javascript

When a store is selected I would only like to see the taxonomies that belong to the selected store. Does anyone have any idea how I might do this? Either with Ruby or Javascript
<h3>Stores Offered In</h3>
<ul class="multi-column-checkbox">
<% for store in Store.all %>
<li><%= check_box_tag "idea[store_ids][]", store.id,
#idea.stores.include?(store) %> <%= store.name %></li>
<% end %>
</ul>
<br />
<h3>Taxonomies Offered In</h3>
<% for store in Store.all %>
<% if store.has_taxonomies? %>
<ul class="multi-column-checkbox">
<h4><%= store.name %></h4>
<% for taxonomy in store.taxonomies %>
<li><%= check_box_tag "idea[taxonomy_ids][]",
taxonomy.id, #idea.taxonomies.include?(taxonomy) %> <%= taxonomy.name %></li>
<% end %>
</ul>
<% end %>
<% end %>

Ok -- lots going on here. First of all, I'm making the assumption that you're using rails 3 or rails 4
Also it looks like this is nested into the ideas model, which not taken into account here, you'll have to modify the code for that.
Firstly - Try not to make calls directly to a model in a view unless you absolutely have to, that should be done in your controller. Also, in your view make sure you have a binding element for taxonomies for the jquery call you'll make later.
your_main_view_referenced_in_your_question.html.erb
<h3>Stores Offered In</h3>
<ul class="multi-column-checkbox">
<%- #stores.each do |store| %>
<li>
<%= check_box_tag "store[ids]", store.id, false, :data => {:remote => true, :url => url_for( :action => 'get_taxonomies', :id => store.id ), :method => :put}, :class => 'input-large' %>
<%= store.name %>
</li>
<% end %>
</ul>
<br/>
<div id="taxonomies">
</div>
Next you need to create a controller action to respond to your ajax call.
stores_controller.rb
### Add an action to let you do an ajax call
def get_taxonomies
#store = Store.find params[:id]
end
Now you need to create a ujs file that is rendered from your controller action In my example I named the controller action get_taxonomies so by default the view rendered will be get_taxonimies.js.erb
get_taxonomies.js.erb
if ($(".store_" + <%= params[:id] %>).length) {
$(".store_" + <%= params[:id ] %>).remove();
} else {
$('#taxonomies').append("<%= escape_javascript(render(partial: '/stores/taxonomy', locals: {stores: #stores } )) %>");
}
if ($("[class^=store_]").length > 0) {
if ( $('#taxonomies').find('h3').length ) {
// do nothing - leave the h3 where it is
} else {
$('#taxonomies').prepend("<h3>Store Taxonomies</h3>");
}
} else {
$('#taxonomies').find("h3").remove();
}
Now while you could write all your html inline in the js file, it's kind of ugly and easier to edit it later if you put it in a partial - since the js.erb file is calling taxonomy, you'll need a partial with the same name
_taxonomy.html.erb
<div class="store_<%=#store.id%>">
<h4><%= #store.name %></h4>
<ul class="multi-column-checkbox">
<%- #store.taxonomies.each do |taxonomy| %>
<li>
<%= check_box_tag "[taxonomy_ids][]", taxonomy.id, false %>
<%= taxonomy.name %>
<% end %>
</li>
</ul>
</div>

Related

How to check policies for objects created through AJAX

In my program one Board can have many Sections. On Boards#show I list all Sections for this Board. A user can create, edit and delete Sections for Boards this user has created.
I use Pundit for my authorizations.
My problem is that after having added AJAX to the create Section action, my policy checks don't work anymore. The AJAX call is working fine in that Sections are added but the "Edit" and "Delete" links are only displayed after I reload the page.
Boards#show
<% if policy(#board).edit? %>
<p><strong>Create a new Section</strong></p>
<%= render 'sections/shared/form', board: #board, section: #section %>
<% end %>
<br>
<p><strong>Sections</strong></p>
<div id="sections">
<% #board.sections.order(id: :asc).each_with_index do |section, index| %>
<span><%= "#{index + 1}. #{section.title}" %></span>
<% if policy(section).edit? %>
<%= link_to "Edit", edit_board_section_path(#board, #board.sections[index]) %>
<% end %>
<% if policy(section).destroy? %>
<%= link_to("Delete", board_section_path(#board, #board.sections[index]), method: :delete) %>
<% end %>
<br>
<% end %>
</div>
Form partial
<%= simple_form_for([#board, #section], remote: true, authenticity_token: true) do |f| %>
<%= f.input :title, id: "section_title" %>
<%= f.submit "Save" %>
<% end %>
AJAX call
var newSection = "<span><%= "#{#board.sections.length}. #{#section.title}" %></span><br>";
var sections = document.getElementById('sections');
sections.insertAdjacentHTML('beforeend', newSection);
var sectionTitle = document.getElementById('section_title');
sectionTitle.value = '';
I think the problem is that the newly created Section isn't inserted into the loop and thus the policy cannot be checked. How could I refactor my code to solve this?
You should be able to render you HTML templates into your js.erb file. See the post from the DHH https://signalvnoise.com/posts/3697-server-generated-javascript-responses how to use this properly. It is an older post so maybe some things changed but you should know what to search for. But if it still works this way, you should be able to do something like this:
Extract section to a partial _section.html.erb
<span><%= "#{index + 1}. #{section.title}" %></span>
<% if policy(section).edit? %>
<%= link_to "Edit", edit_board_section_path(#board, #board.sections[index]) %>
<% end %>
<% if policy(section).destroy? %>
<%= link_to("Delete", board_section_path(#board, #board.sections[index]), method: :delete) %>
<% end %>
<br>
Use this partial also in your Boards#show file.
Render your partial in the js.erb file
var newSection = "<span><%=j render #section %></span><br>";
Something like this should work, but I don't use server generated javascripts so they could have changed some things. But hopefully it will help you at least with the direction.

Rails/JS button onclick to re-render partial without entering into DB

I wish to reload a partial-form with a button(Add). I'm new and don't know how to simply display fields in partial like listings one under the other as many times Add button is clicked. I can't find a relevant example. all AJAX examples mention js.erb when object is saved in DB.
<div class="panel-body">
<%= render partial: "degrees/form", :locals => { :f => f } %>
<%= f.link_to (fa_icon 'plus').to_s + " Add Another Qualification ", render(:partial => 'degrees/form', :locals => { :f => f }), class: "btn btn-primary" %>
</div>
Here, #application is the main form trying to display degree fields. Partial is simply two text-fields- one for selecting educational degree and second its detail.Here's partial
<%= f.fields_for [Degree.new], :url => { :action => "index" } do |ff| %>
<div class = "form-group" }>
<%= ff.select :level, options_for_select(Job::EDUCATION, params[:level]), include_blank: "Select Degree", class: 'span-2' %>
<%= ff.text_field :description, :class => 'span5' %>
</div>
<% ff.submit "Add Another Degree", class: 'btn btn-primary' %>
You don't necessary need to save things to pass away to .js.erb... you can just instantiate...
But if your example is precise, you are missing the remote: true flag for the link... And the partial is not defined on the link... you need to make a view responding to the ajax...
Form example
<div class="panel-body">
<%= link_to new_thing_path, remote: true do %>
<i class="fa fa-plus">
Add another qualification
<% end %>
<div class="new-things-container">
</div>
</div>
Controller answering to the ajax request
class ThingsController < ApplicationController
def new
#thing = Thing.new
respond_with #thing
end
end
View for the ajax request rendering a partial inside a specified div
//views/things/new.js.erb
$('.panel-body .new-things-controller').append("<%= render partial: 'degrees/form', locals: { thing: #thing } %>")

Rendering partial with remote: true if i have few same ids

I have a problem with rendering data on my page through remote: true.
I have a comments and subcomments (comments to the comments). When I click "Comment" button under the second Post, a comment appears below the first because I have a few same ids "comment-list" in my loop. How I should fix this? P.S Sorry for my english :)
Here is how look my Post and Comments form:
<% #posts.each do |post| %>
<li class="post">
...
<% if current_user == post.user %>
<%= link_to "delete", post, method: :delete, remote: true %>
<% end %>
</li>
<div id="comments-list">
<%= render partial: 'post_comments/comments', locals: { post: post } %>
</div>
<% if user_signed_in? %>
<div id="comment-form">
<%= render partial: 'post_comments/new_comment_form', locals: { post: post } %>
</div>
<% end %>
And here is how looks my create.js.erb
$('#comments-list').html("<%= j (render partial: 'post_comments/comments', locals: { post: #post }) %>");
What I've done in a similar situation is make your div IDs specific to each post:
<div id="comments-list-<%= #post.id.to_s %>">
and then in your jquery code specify the relevant post:
$('#comments-list-<%= #post.id.to_s %>').html("<%= j (render partial: 'post_comments/comments', locals: { post: #post }) %>");
Let create a wrapper specifying your post
<% #posts.each do |post| %>
<div id="post_<%= post.id %>">
<!-- Your current code here -->
<div>
<% end %>
Use comments-list as class instead (the same apply for comment-form)
<div class="comments-list">
<%= render partial: 'post_comments/comments', locals: { post: post } %>
</div>
Finally your jquery selector in erb will be:
$("#post_<%= #post.id %> .comments-list")

Passing specific data on partials using Ajax in Rails

I'm new to rails and what I'm trying to do is the following:
I'm creating a store and unstore button to save and 'un-save' the event respectively. I used my event attributes and current user to find that stored event. By using ajax and remote functionality of rails I will able to change the behavior of the button from store to unstore or vise versa.
In my _feed.html.erb.
<% if #feed_items.any? %>
<ul>
<%= render partial: 'shared/feed_item', collection: #feed_items %>
</ul>
<% end %>
Each #feed_items contains set of data (title, category, etc).
In my _feed_item.html.erb.
<li id="<%= feed_item.id %>" class="item">
...
<div class="small-3 text-center columns">
<%= render 'shared/store_form', event: feed_item %>
</div>
...
</li>
Event symbol sends that feed_item to the store_form.
In my _store_form.html.erb.
<div id="store_form_<%= event.id %>">
<% if event.stored?(current_user) %>
<%= render 'shared/unstore', event: event %>
<% else %>
<%= render 'shared/store', event: event %>
<% end %>
</div>
I pass again a feed_item into partial.
_store.html.erb
<%= form_for(event.storages.build(saver_id: current_user.id,
organizer_id: event.user_id),
remote: true) do |f| %>
<div>
<%= f.hidden_field :organizer_id %>
<%= f.hidden_field :saved_id, value: event.id %>
</div>
<%= f.submit "store" %>
<% end %>
_unstore.html.erb
<%= form_for(event.storages.find_by(saver_id: current_user.id,
organizer_id: event.user_id) ,
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit 'unstore' %>
<% end %>
create.js.erb
$("#store_form").html("<%= escape_javascript(render 'shared/store', event: event )%>")
destroy.js.erb
$("#store_form").html("<%= escape_javascript(render 'shared/unstore', event: event) %>")
And I'm getting these errors when clicking store/unstore event.
ActionView::Template::Error (undefined local variable or method `event' for #<#<Class:0x00000004d69be8>:0x00000004d68d10>):
1: $("#store_form").html("<%= escape_javascript(render 'shared/unstore', event: event) %>")
ActionView::Template::Error (undefined local variable or method `event' for #<#<Class:0x00000004d69be8>:0x00000004fdc6a0>):
1: $("#store_form").html("<%= escape_javascript(render 'shared/store', event: event )%>")
My question is, how can I pass that specific "event" data into the partial. I can't used #feed_item onto the create and destroy js because feed_item have the set of events. Is there any better approach to handle this?
In your action create and delete in the controller you should instantiate your variable event: change event by #event and change your js to:
$("#store_form").html("<%= escape_javascript(render 'shared/unstore') %>
because you donĀ“t need add instantiate vars to render calls, rails is doing for you

In my comment app when i refresh the page comments disappears

My comment app works ,but the only problem is whenever i refresh the page the comments disappear.In the log it shows the body is inserted in the comments table(it is saved).What am i doing wrong here?Any help will be appreciated.Thank you in advance.
View#show
<div id="comments"></div>
<%= form_for :comment,:remote => true,:url=> {:controller=>"comments",:action=>"create"},:html => { :id => 'new-comment'} do |f| %>
<%= f.text_area(:body) %>
<div class="errors"></div>
<%= f.submit "post" %>
<% end %>
Comment controller
class CommentsController < ApplicationController
respond_to :js
def create
#deal=Deal.find(1)
#comment =#deal.comments.build(params[:comment])
#comment.save
respond_with( #comment, :layout => !request.xhr? )
end
def show
#comment=Comment.all
#deal=Deal.find(1)
#comment=#deal.comments
end
end
create.js.erb
$('#comments').append("escape_javascript(#comment.body)");
I don't see where your comments are being display in your show template.
How about something like this?
<div id="comments">
<% #comments do |comment| %>
<%= comment.body %>
<% end %>
</div>
<%= form_for :comment,:remote => true,:url=> {:controller=>"comments",:action=>"create"},:html => { :id => 'new-comment'} do |f| %>
<%= f.text_area(:body) %>
<div class="errors"></div>
<%= f.submit "post" %>
<% end %>
Note, you need to set #comments in the controller or use another method of getting comments, e.g. #view = View.find(params[:id]) and <%= #view.comments.each do |comment| %>...
I guess the comment has a belongs_to relationship with the post that is not assigned.
In your form you should add
<%= f.hidden_field :post_id, #post.id %>
If you want to play by the book, post_id should be attr_protected and instead assign it manually in the comments controller
#comment = Comment.new(params[:comment])
#comment.post_id = params[:comment][:post_id]
#comment.save

Categories

Resources