How to pass object to partial using controller? - ruby-on-rails

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

Related

putting form for new inside other view from different controller

I have created an app which has a user, user can have many players and each player can have many abilities. Now in my player show view, I can see information about a player and his abilities, but also I want to have a form for creating/updating abilities for that player. How do I implement a view from abilities controller to player show view so i can create/edit and delete his abilities directly from there via ajax? I was thinking about making new.html.erb from abilities a partial and then render it into show.html.erb but what do I put in form_for so that rails knows that its supposed to communicate with different model and controller? Whats the right way of doing this?
First of all, there is no problem in adding the form_for for the associated model(Ability) in show of Player. You can make a partial of the form, and render it for all its abilities.
In controller,
#abilities = #player.abilities
And in show,
#Some code to show player details
<% #abilities.each do |ability| %>
<%= render 'ability', ability: ability%> #Pass local variable ability to partial
<% end %>
And make partial using form_for tag with AJAX in init to update the information. Also, you can define 'action' of form_for tag using
form_for(ability,:url => url_for(:controller => 'abilities', :action => 'update')
You can place the partial of ability in abilities folder corresponding to Abilities Controller and give its relative path in the above render statement as:
<%= render '/abilities/ability', ability: ability %>

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

Declare a variable in Link so Controller loads separate layout in Rails

I have a link that calls this:
<%=link_to 'Free Trial', '/sign_up', :rel => "#signup", :class => "sign_up_button"%>
Which renders mysite.com/sign_up - This loads a partial in a Jquery light box. However What I would love to do is have a controller statement where if the link above is clicked it renders the page with no layout. But if the user navigates to mysite.com/sign_up from the address bar, they see the same page but with a layout.
I am thinking in my controller something like this:
def sign_up
if :variable == true
render :layout => false
else
render :layout => 'layouts/sign_up'
end
end
then in my link declaring a variable it can pass to the controller? something like
:variable => 'true'
I am thinking about this in the right way? How would the above work?
The main reason for this is so that if mysite.com/login is loaded on its own (without Jquery) then it will still look good!
Thanks
You have two ways :
You can do as you are thinking, and set your partial flag via POST. Replace /signup with /signup?partial=1 and in your controller if params[:partial]
Or you can render conditionnaly looking at request.xhr? (but ajax headers must be setted correctly by your js framework)

how can I cache a partial retrieved through link_to_remote in rails?

I use link_to_remote to pull the dynamic contents of a partial onto the page. It's basically a long row from a database of "todo's" for the day.
So as the person goes through and checks them off, I want to show the updated list with a line through those that are finished.
Currently, I end up needing to click on the link_to_remote again after an item is ticked off, but would like it to redirect back to the "cached" page of to-do's but with the one item lined through.
How do I do that?
Here is the main view:
<% #campaigns.each do |campaign| %>
<!--link_to_remote(name, options = {}, html_options = nil)-->
<tr><td> <%= link_to_remote(campaign.name, :update => "campaign_todo",
:url => {:action => "campaign_todo",
:id => campaign.id
}
) %> </td></tr>
<% end %>
</table>
<div id="campaign_todo">
</div>
I'd like when the New/Create actions are done to go back to the page that redirected it there.
When someone wants to "do" a task, it takes them to the new action. here is the controller:
def create
#contact_call = ContactCall.new(params[:contact_call])
if #contact_call.save
flash[:notice] = "Successfully created contact call."
redirect_to contact_path(#contact_call.contact_id)
else
render :action => 'new'
end
end
I switched to redirect_to :back, which takes me back to the main view shown above...but WITHOUT the PARTIAL. It means I need to reload the partial all over again, which is a time-consuming database call.
1) Is it possible to go back to a view that has a partial called through AJAX and still have those results show up?
2) Can that result, however, be marked via CSS to indicate that it has been "checked off"?
I would render the to-do list item response from javascript ERB files. So when you make the link_to_remote call, instead of redirecting back to the page, instead render javascript.
You'd have the form in /app/views/contact_call/_form.html.erb
/app/views/contact_call/create.js.rjs
page.replace :contact_form, :partial => "contact_call/form", :locals => { :user => #user }
page.visual_effect :highlight, :contact_form
Your controller would then render the javascript, which would in turn replace html on your page with the latest version (and highlight it). And your page would load the partial with strike-through on completed items.
you have to create an ajax call when you mark one item as 'done', in this action you'll need to
update your list item to add the 'line-through' to text-decoration
create a method like 'after_save', to expire your cache
you can read about the CSS 'line-through' here:
http://www.icelab.eu/en/blog/css-4/xhtml-and-css-strike-alternatives-86.htm
and the documentation for expire_page and expire_action is here:
http://api.rubyonrails.org/classes/ActionController/Caching/Sweeping.html
I think you may be able to use action caching on your index action, or whatever the name of the action is that renders your main page.
You can also do page caching and fragment caching, which would work with partials. For more information on Rails caching strategies, see the rails guide:
http://guides.rails.info/caching_with_rails.html

Resources