Rails: Populating modal with data - ruby-on-rails

I know this is an old question, but I cant get it solved..
I want to show a list of comments in a modal, specific to each iteration.
Content has_many comments, Comment belongs_to content`
#contents.each do |content|
content.title
button_to('read', category_modal_path(:comment_id => content.id), remote: true, :class=> 'modal-trigger2', 'data-target'=>'modal3')
end
controller
def category_modal
#comments = Comment.online.where(content_id: params[:comment_id])
respond_to do |format|
format.js
end
the modal
<div id="modal3" class="modal modal-fixed-footer">
...here I want show the list of comments
category_modal.js
$('#modal3').html(<%= j( render partial: 'shared/modal2', locals: {comments: #comments} )%> );
coffee
$('.modal-trigger2').leanModal()
Modal opens but no data.. help would be very nice..

Okay after an hour efforts I am able to solve your issue. Follow these steps.
First of all remove $('.modal-trigger2').leanModal() from coffee script. It does not need any more.
In category_modal.js paste the following code
$('#modal3').html("<div href='#modal3' id='content_<%=params[:comment_id] %>'><%= j( render partial: 'shared/modal2', locals: {comments: #comments} )%></div>");
$('#content_<%=params[:comment_id]%>').leanModal();
$('#content_<%=params[:comment_id]%>').trigger('click');
You might need to add method: :get on your category listing If your route is not of post type so
#contents.each do |content|
content.title
button_to('read', category_modal_path(:comment_id =>content.id), remote: true, :class=> 'modal-trigger2',method: :get)
end
okay now tell me what was the issue.
Basically it was the mess of leanModal If you have used bootstap modal it would not be the problem.
Basically Whenever we call leanModal on any element It stops it default behaviour i-e Click So from now on when some one click on it , It open the popup in which it shows the corresponding content which was mentioned in href of the clicked item.
So when I call $('.SomeClass').leanModal() It will add a click event for all of the item having class SomeClass and open modal when some one click on it and show the content.
So in your case when you called $('.modal-trigger2').leanModal() It simply added a click event for all of your Contents buttons and open the popup whenever you clicked on any of it. It even didn't send an ajax call to server.
As you know initially there was not any content in modal3 container that's why it opened empty modal.
So now what I did was to remove this call and moved all of the popup logic in category_modal.js
So whenever you click on a Content it send an ajax request to server. In JS view I am doing the same thing you were doing but now I added a wrapper around your comments and set the ID unique depending on your requested content_id .
After that I call leanModal on this newly created wrapper div.
And trigger the click event on it so modal will show automatically.
P.S
You don't necessarily need this dynamic ID stuff following code will also work .
$('#modal3').html("<div href='#modal3' id='leanModalContainer'><%= j( render partial: 'shared/modal2', locals: {comments: #comments} )%></div>");
$('#leanModalContainer').leanModal();
$('#leanModalContainer').trigger('click');

Related

How to pass object to partial using controller?

I've been trying to pass my Product object to my rendered partial but no matter what I try it doesn't work. The home page has a quick view button that pops a modal (the partial) and I want to pass the correct product to it.
Route
get 'shop-product-ajax-page', to: "pages#shop_product_ajax_page"
Home Page (shortened to only the link for brevity)
<% #products.each do |product| %>
<%= link_to "Quick View", shop_product_ajax_page_path, :data => {:lightbox => 'ajax'} %>
<% end %>
Controller Action
def shop_product_ajax_page
render :partial => 'pages/shop_product_ajax_page', :layout => false
end
Right now, the button works and displays the HTML in the modal. I want to be able to populate the correct product information for whatever Quick View product is selected.
The problem is that the link is making a completely separate AJAX request, it's hitting the server separately, so the Ruby context you expect (variables etc) isn't available in that new request.
Two choices:
Don't make an AJAX request but render the lightbox as part of the page. You could hide it using display: none or similar, then use Javascript to display it when the link is clicked.
Make the request the way you currently are, but pass in the same parameters that your current controller action is using to get #products and in shop_product_ajax_page do the same thing to hit the database and get the products.
The second choice might be easier without messing with JS. It would be something like:
def shop_product_ajax_page
#products = get_products_from_params(params)
render :partial => 'pages/shop_product_ajax_page', :layout => false
end
private
def get_products_from_params(params)
Product.find(params["product_ids"]) # or whatever you're currently doing
end

Rails: Why do I get a 204 response from all but the first request?

I have a button on my homepage. When clicked it makes a POST request to forms_controller so that a new form is created.
My button:
<%= link_to 'Add form', forms_path, id: 'add_form_button',
class: 'btn btn-primary',
method: :post, remote: true %>
When the request is completed, a message is logged to the console:
<script>
$('#add_form_button').on('ajax:complete', function(){
console.log('Request complete!');
});
</script>
This is the action:
def create
current_user.forms.create
end
My routes are defined like so:
Rails.application.routes.draw do
devise_for :users
root to: 'home#show'
resources :forms, except: [:index]
get 'user_forms' => 'partials#user_forms'
end
It works as expected. Each time I click the button, a new form is created and the message is logged to the console.
However, after the form is created, I want to reload a div so that I can see the newly created form listed with any others:
$('#add_form_button').on('ajax:complete', function(){
console.log('Request complete!')
var user_forms = '#user_forms';
$(user_forms).load('user_forms',function(){
document.getElementById('add_form_button').scrollIntoView();
});
});
In the case of .load('user_forms')..., user_forms is a route to an action that I have created to return a partial:
class PartialsController < ApplicationController
def user_forms
render partial: 'home/user_forms'
end
end
The first time the button is clicked, it works as expected: a new form is created, the message is logged to the console and the div is reloaded with the partial so that it lists the newly created form.
But it doesn't work on subsequent clicks. New forms are created on each click of the button but the div does not reload nor is the message logged to the console. I also see the following error in the Rails terminal:
No template found for FormsController#create, rendering head :no_content
Completed 204 No Content in 454ms (ActiveRecord: 2.6ms)
I understand that I have not defined an explicit response in forms_controller#create but I don't understand why it works the first time and not subsequent times. What is stopping it from working a second time?
ok, I whipped up a quick example(using what you provided), and it works fine for me. Notice you should only see 2 requests for each click. Do you see other warnings, errors?
I made a simple user_form partial to prove the form is ajax loaded.
<table>
<% Form.all.each do |f| %>
<tr>
<td><%= f.id %></td>
<td><%= f.name %></td>
</tr>
<% end %>
</table>
So, your code is fine :). I'd recommend looking at other culprit like turbolink(it can mess up your ajax), custom js script etc.
The error is telling you that FormsContoller#create doesn't have a template. Because you didn't put an explicit render in that action, Rails is trying to find a template under forms/create.html.erb.
But of course you don't want to render a template for your create action because it's only responding to an AJAX post.
Try adding an explicit render at the end of the FormsContoller#create action. Something like render {}, status: :ok.
Not sure if that resolves your form rendering issue but at least that should resolve the No template found error.
Firstly, the premise of my question is completely wrong. I get a 204 after every click but a GET request with a 200 status follows the first click. I assumed the 200 was for the first POST. Kasperite's advice that I should see two requests for every click helped me realise the obvious.
I hadn't explained in my question that the button itself was in the user_forms partial that was being used to populate the reloaded the div. (If I'd mentioned it, I would have likely seen the problem straight away. Besides, the name I'd given the partial itself should have been a big enough clue it shouldn't have been in there.)
Whilst $('#add_form_button').on('ajax:complete', function(){...} works the first time, the original button is removed from the DOM and is replaced with an identical one.
However, since this is an entirely different element, the event listener is not attached to this new button.
I have solved the problem by simply placing the button outside of the partial.

Rails partial from different controller in a Bootstrap tab

I have a Home page with 2 Bootstap tabs. I'm having problems with the 2nd tab. I'm trying to render a list of workorders. For that list I'm using dataTables and ajax.
My issue is that workorders/index7.html.erb works fine as a stand alone page. But, I want to use it in a Bootstrap tab on the Home page.
For all my other Bootstrap tab lists, I'm using partials from within the same controller. But, in this case, I need to use a view from the Workorder controller not the Home controller.
This is the code I'm trying in the Home view:
<div class="tab-pane" id="tab2">
<%= render "workorders/index7" %>
</div>
That code gives me:
Missing partial workorders/index7
WHY? If I change the file name to _index7.html.erb the code won't execute to get the json.
But, because it's a partial, starting with _, the connection to the Workorder controller code for index7 doesn't work. I also tried _index7 in the Workorder controller.
The Workorder controller has this code:
def index7
#workorders = Workorder.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: Workorders3Datatable.new(view_context) }
end
end
That code uses a file called workorders3_datatable.rb to get the data via ajax and format it for dataTables.
QUESTIONS:
1) Do I have to use a partial in the Home tab? Or is there a way to render a file called workorders/index7.html.erb in the tab?
2) Why does index7.html.erb use the controller code for index7, yet the partial _index7.html.erb won't use code if I call it _index7 in the controller?
3) I read this "Render will just render the view, it won't run the action associated with it." - is that true?
Thanks for your help - I know this is confusing.
Reddirt
UPDATE 1
The view runs great as workorders/index7 - but, if I change it to a partial and put it in a tab = workorders/_index7 - the controller code for index7 doesn't seem to execute.
1) Do I have to use a partial in the Home tab? Or is there a way to view a file called workorders/index7.html in the tab?
If you want to follow this approach. From Home controller pass the collection (#workorders = Workorder.all)
Then in the home view pass it to the workorders/index7 as locals
<div class="tab-pane" id="tab2">
<%= render "workorders/index7" locals: {workorders: #workorders} %>
</div>
This will make it available to workorders/index7 do remember to change the variable to a local variable workorders.
You need to include :partial in the view for your Home page:
<%= render :partial => "workorders/index7" %>
The app/views/workorders folder will need a file called _index7.html.erb. To accomplish this from your current setup, you can move the contents of index7.html.erb into this partial, and then use:
<%= render :partial => "index7" %>
in the original index7.html.erb. That way you can render that as a whole page and within your Home page as a partial.

Add section to form by rendering a partial when link is clicked

UPDATE 3:
For anyone who reads this, this is why it wasn't working as expected in update 2 below: Passing a local variable to a partial that is rendered after the view has already loaded
If anyone knows how to solve that issue, let me know please.
UPDATE 2:
I updated the javascript with the quotation marks and it partially works...in the sense that the javascript is now functional and it will cause a string of text to appear on the page when I click the link as long as I have the partial only contain a string of text. However, when the partial includes the form fields code, something goes wrong.
If I just paste the following render code directly into the form in the new.html.erb view, it produces a new form section properly.
<%= render "add_round", f: f %>
However, when I try to include similar code in comps_helper.rb and then reference it from the link_to, it does not work:
In comps_helper.rb:
def addRound(f)
render "add_round", f: f
end
In new.html.erb:
<%= link_to "render it!", addRoundLink_path, remote: true %>
<div id="some_id"></div>
And I changed addRoundLink.js.erb to:
$("#some_id").html("<%=j addRound(f) %>"); #Is this the correct change to have made here?
Clicking the link_to link does nothing in that case.
Any thoughts?
UPDATED CODE:
Thanks for the reply. I've made the following changes and it still does not appear to be working. The link appears at the bottom of the form but when clicked does not change anything. What am I missing?
routes.rb:
resources :comps
match '/new_competition', :to => "comps#new"
get "/addRoundLink" => "comps#addRoundLink", :as => :addRoundLink
Note: I included the other 2 lines related to "comps" just in case those would cause an issue.
comps_controller.rb:
def addRoundLink
respond_to do |format|
format.js
end
end
comps_helper.rb:
def addRound
render "add_round"
end
addRoundLink.js.erb:
$("#some_id").html(<%=j addRound %>);
comps/new.html.erb:
<%= link_to "render it!", addRoundLink_path, remote: true %>
<div id="some_id"></div>
Thanks.
ORIGINAL QUESTION
First off, I'm new to rails. I've read and tried many solutions to similar questions but nothing has worked so far.
I created a form with rails form_for and fields_for. The form creates a new competition (comp). The competition has many rounds. The top half of the form (the form_for section) accepts the details about the competition as inputs and the bottom half of the form accepts details about each round (the fields_for section). The form works perfectly in this basic format.
I took all the code that is in the fields_for section and put it into a partial. My plan was to then create a "add new round" link to the bottom of the form that would simply display the partial above the link each time the link is pressed. This would add a new section to the form for a new round and allow the user to input as many rounds as they'd like. This is the part that I am struggling to make work.
I added this code to my comps_helper:
def addNewRound
render "add_round"
end
This renders the file /views/comps/_add_round.html.erb.
My question is: how do I get this to render in the form when a link is clicked. As far as I can get with the research I have done is:
<%= link_to "Add new round", { }, :remote => true %>
I don't exactly know what is supposed to go in the {} that will execute the addNewRound method. And I don't know what, if anything, I need to add to my comps_controller file.
Thanks so much for the help.
You have to create an action in your controller
app/controllers/some_controller.rb
def hello
respond_to do |format|
format.js
end
end
and define a route to this action.
routes.rb
get "/hello" => "some#hello", :as => :hello
then create a link to this action like that:
<%= link_to "render it!", hello_path, remote: true %>
<div id="some_id"></div>
When you click this link it will find its way to your action and respond with js(javascript) because we told action to respond with only js.
At the end render the partial to anywhere you want in your view(*in this example to the some_id div*)
app/views/some/hello.js.erb
$("#some_id").html("<%=j addNewRound %>");
WARNING: Creating dynamic forms is a pain. You will face a lot of problems (like setting different ids for new form elements etc...). I highly recommend you to use ryan bates nested_form gem

Posting a form through popup in Rails

I have a model called Details, and two controller methods new and create. New method displays a form to create Details (in new.html.erb), which gets posted to the Create method that saves it. (when it succesffully saves, it it renders the new.html.erb file with the details.) This works as expected.
Now i want a separate page with a link to fill in these details. I want the click to do the intended work through a popup, example redbox. When you click on that link, a popup should show the form, whose submit should post the form, and if it is successfully done, then refresh the original page. If the post is unsaved, then the same form should show the errors. What do i need to do to make it work in Ror? I guess i need some stuff to go in new.js.rjs and maybe create.js.rjs, but i can't really figure out what to put in those files.
Redbox updates the page's dom to add a div at the end of it. So your form is a part of the main page.
So if you add a form tag in this redbox, all your page will be reloaded as there's only one.
So you add anywhere in your page (preferably at the end) :
<div id="redbox" style="display: none;">
<%= form_for #details do %>
# Whatever form fields you want here
<% end -%>
</div>
You do a link that'll open the redbox :
<%= link_to_redbox 'Open The Details Form', 'redbox' %>
This will display your redbox with your form.
And as it is the same page, not a new windows, when you'll validate your form, it'll reload the all of it.
I used a link_to_remote_redbox for this, which on clicking, fetches the form rendered by the new method call in a popup widnow. it submits to the create function and it is now working. actually i had previously made it work without ajax and i was having difficulty in making it work with ajax. the problem was solved once i made separate partials for ajax calls, and doing:
respond_to do |format|
format.js { render :template => 'detail/ajax_template'}
...
end
I provided different templates for both create and new method calls, used the :html => {:id => 'some-id'} in form and the :update => {:some-id} to replace the form with the message that it worked correctly.
So I didnt know that i needed separate templates for the different styles of forms, and that i needed to use the :update option to replace the form when i asked the above question.

Resources