I have my show action within a partial called properties/_property_details.html.erb that I'm trying to display with ajax within the index action's view.
properties/index.html.erb:
<div id="showdiv">
<%= render :partial => 'property_details' %>
</div>
properties/_property_details.html.erb:
<div id="response">
<h3>
<%= [#property.Address,#property.City,"FL"].join(", ") %> <%= #property.Zip %></h3>
etc etc </div>
However, when I try to load the index page the #property variable of the show action is nil so I get an
undefined method `Address' for nil:NilClass
presumably because there is no (params[:id]) for the show action as required in the properties_controller:
def show
#property = Property.find(params[:id])
respond_to do |format|
format.js {render :partial => 'property_details' ,:layout => false}
format.html
end
end
But if that's the case then I should be able to hard code a value for #property in the show action just to test this but the following code still gives the same undefined method for nilclass error when I try to load the index page containing the partial:
def show
#property = Property.find(1)
respond_to do |format|
format.js {render :partial => 'property_details' ,:layout => false}
format.html
end
end
Why is #property coming back as nil? I opened the rails console and did p = Property.find(1) and got a property returned so for some reason the partial isn't listening to the show action in the controller when it's within my index page.
The partial works fine when it's within the properties/show.html.erb like this:
<div class="twothirds">
<%= render :partial => 'property_details' %>
</div>
<div class="onethird">
<%= render :partial => 'property' %>
</div>
So it's only when I'm trying to put the partial within my index page that it doesn't work. What am I doing wrong?
This is my first attempt at Ajax so I was mistakenly including the partial for the show action in the index action before the user had clicked on a link to display the show action. So I've replaced the partial in the index action with just an empty div and I replace the empty div with the partial through ajax only when the user clicks on a property link to view a property through the show action.
Related
I have a property search page (:controller => 'properties', :action => 'index') that consists of a right sidebar that has a search form which displays the search results below the form. When the user clicks on a property in the right sidebar I want to display the details of that property in the main area of the index page on the left.
Right sidebar is a partial called properties/_property.html.erb:
<%= form_tag properties_path, :method => 'get' do %>
<%= text_field_tag 'location', (params[:location]) %>
<%= select_tag(:max, options_for_select([['No Max', ""], ['$100,000', 100000], ['$200,000', 200000], etc %>
more search fields for baths beds etc
<%= submit_tag "Search", :name => nil %>
<% end %>
<% #properties.each do |property| %>
<%= link_to([property.Address,property.City].join(", "), {:action => 'show', :id => property.id}) %>
<li><strong><%= number_to_currency(property.Price, :precision => 0) %></strong></li>
etc etc
<% end %>
The only way I know how to show the property details is with the 'show' action, but that takes the user to a new page, for example localhost:3000/properties/1865. I've made the 'show' view with the same layout as the 'index' view and have made the right sidebar a partial (properties/_property.html.erb) which appears on both 'show' and 'index' so when the user clicks on a property in the right sidebar and goes to localhost:3000/properties/1865 the property details are displayed correctly in the main area and the right sidebar is on the right.
But because localhost:3000/properties/1865 is a different page than localhost:3000/properties/index the search form in the right sidebar has forgotten it's parameters which means the list of search results in the right sidebar has changed back to the default list of all properties.
How can I display the 'show' action within a partial on the index page so the user's search parameters are remembered by the form in the right sidebar? Or if I have to go to the 'show' page how can I make the right sidebar stay exactly as it is?
Any ideas greatly appreciated, just a suggestion in the right direction would be good, have spent all day trying to figure it out and have got nowhere, thanks
I have made the show view with the same layout as the index view and
have made the right sidebar a partial (properties/_property.html.erb)
which appears on both show and index.
Yes but this will only get you a similar layout for both the pages. You want the list to persist between different requests.
You basically have two options. use session to remember the list which I wont recommend.
Other is you use form :remote => true or ajax and update the page partially.
EDIT:
What version of rails you are using? Do u have jquery loaded in your application?
Follow this SO POST.
You might have to change your show action a bit.
respond_to do |format|
format.js {render :partial => 'property_details' ,:layout => false}
format.html
end
Create a partial for property details and just put body content here.
And link will look like
<%= link_to "link name", {:action => :show, :id => item_id}, :remote => true ,:html => {:class => 'links_product'} %>
Also to update the view you may use(make sure you have rails.js in your page):
$(document).ready(
function(){
$("a.links_product").bind("ajax:success",
function(evt, data, status, xhr){
$("#response").html(data); // in case data is html. (_*.html.erb)
}).bind("ajax:error", function(evt, xhr, status, error){
console.log('server error' + error );
});
});
Have a div with id response or any valid id. Done!
This is my form, and it works fine, but now I want to AJAX it.
<%= form_tag variant_path(variant.id), :method => :put, :class => 'update_inv_form' do %>
<%= text_field_tag :inventory_quantity, variant.inventory_quantity %>
<%= submit_tag 'Update' %>
<% end %>
When I add the :remote => true attribute the form successfully submits via AJAX (I can see it happening on the server and I can see the changes when I refresh the page). I want to update the view properly to show the changes without refreshing the page. This is my update action: (Note that I am not working with ActiveRecord Models here.)
def update
variant = ShopifyAPI::Variant.find(params[:id])
variant.inventory_quantity = params[:inventory_quantity]
variant.save
redirect_to root_path
end
UPDATE
Thank you to the answer that helped me figure this out turns out the solution is exactly as he said, however I ran into a small problem. The view I wanted to update lives in app/views/home/index.html.erb and I was dealing with this: Variants#update. (Variants controller, update action)
I was putting my update.js.html in the same directory that my view was: app/views/home and my server was throwing a 500 error: Missing Template. Turns out, I had to create an app/views/variants/ directory and put the update.js.html file in there. Problem solved.
You'll need to change your action to respond to the JS format:
def update
#variant = ShopifyAPI::Variant.find(params[:id])
#variant.inventory_quantity = params[:inventory_quantity]
#variant.save
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
end
You can then create an update.js.erb file with JavaScript that will update the page. Let's say you have a _variant.html.erb partial, you could append the variant to a div like this (assuming you are using jQuery):
$('.variant-list').append('<%= escape_javascript(render(:partial => "variant", :object => #variant)) %>');
update
Here's an example of how you would use the update.js.erb' file (Note: I have not tried this code). Let's say you have the following code in yourindex.html.erb`:
<ul class="variants">
<li id="101">Variant 1</li>
<li id="102">Variant 2</li>
<li id="103">Variant 3</li>
</ul>
Your updated.js.erb could look something like this:
$('.variants #<%= #variant.id %>').text('<%= #variant.title %>');
What this does is find the variant you just updated in the list, and change the variant title to the new one.
Rails 3.2.1: I have the following div that calls a partial
<div id="weighin">
<%= render :partial => "my_weight/weighin" %>
</div>
The partial contains a form that posts ajax (ie has :remote => true) to a controller with:
respond_to do |format|
format.js
end
The .js.erb file has a single line:
$("#weighin").html("<%= render :partial => "my_weight/weighin1" %>");
The _weighin1.html.erb partial file has a single line:
<p><%= #my_weight[1].weight %></p>
This works, in that the original div is replaced with the value of the #my_weight field - so the fundamental structure is all working ok
However, Rails will not handle any more code in the partial - if I add so much as a carriage return to the end of that one line, the server log confirms all ok, but no script gets run on the page - ie nothing changes.
The same happens if I try to put more html in the partial, but put it all in a single line - this doesnt run either.
How can I output more than a single short statement in a partial?
OK, I figured this out:
$("#weighin").html("<%= escape_javascript(render :partial => "my_weight/weighin1") %>");
escape_javascript is essential
What is confusing is that, depending on what is in the html() you are sending, this will sometimes work without escape_javascript, leading one to a false conclusion... :-)
I'm learning to program and got a form running in my Rails 3 app. Now I'm attempting to add ajax to the form so the page doesn't reload after submitting.
I've followed the numerous tutorials but can't quite seem to figure out how to bring it together. The form adds new Objects to the Profile through the following model:
class Profile < ActiveRecord::Base
has_many :objects
end
class Object < ActiveRecord::Base
belongs_to :profile
end
My form in views/profiles/_object_form.html.erb:
<%= form_for(#object, :remote => true) do |f| %>
<% end %>
Where the form and its created objects are rendered in my views/profiles/_about.html.erb:
<div id="newObjects">
<%= render :partial => 'object_form' %>
</div>
<div id="objectList">
<%= render :partial => 'object', :collection => #profile.objects, :locals => {:object_count => #profile.objects.length) %>
</div>
In my objects_controller.rb I have the following create action:
def create
#object = Object.new(params[:object].merge(:author_id => current_user.id))
respond_to do |format|
if #object.save!
format.html {redirect_to profile_path(#object.profile) }
format.js { render }
else
format.html { redirect_to #profile, :alert => 'Unable to add object' }
end
end
end
In views/objects/create.js.erb:
$('#objectList').append("<%= escape_javascript(render #profile.object)) %>");
So I have a form calling an action in another controller to which I want to add ajax. What happens at the moment is that I need to reload the profile to show the newly created object. What am I doing wrong?
CLARIFICATION: Other than the create action in the ObjectsController, I only reference #object once elsewhere. That's in the ProfilesController's show action:
def show
#profile = Profile.find(params[:id])
#superlative = #profile.superlatives.new`
end
Not sure if this is a full code snippet for your create action, but looks like you are trying to call render on an instance variable that doesn't exist... #profile is never set in the create method in the ObjectController...
Perhaps you meant to type $('#objectList').append("<%= escape_javascript(render #object)) %>");
Also noticed that in your existing code you're making a call to render #profile.object, but the Profile class has a has_many relationship with your Object class, so if that was the right code, then you should type render #profile.objects (plural, not singular).
But I would think you would likely want the code I mentioned above, since you are appending onto the list of objects, not rendering the list again?
I'm using jQuery UI Tabs to handle tabs my Rails 3 app. One tab is without Ajax, one is with Ajax. I'm new to programming and Rails, and while I got a ton of help from SO thus far I'm having two issues:
Clicking my Ajax link loads the entire site's layout in my div. I want to just load my template.
No matter which profile I view, the content loaded only applies to the current_user's messages.
Here's the container for the tabs:
<div id="tabs">
<ul id="infoContainer">
<li>About</li>
<li><%= link_to "Messages", '/profiles/profile_messages', :remote => true %></li>
</ul>
<div id="tabs-1">
</div>
</div>
The second link is where I see the entire site layout. Ideally what I want is to replace the About div with the my profile_messages template.
My profiles_controller.rb:
def profile_messages
#profile = User.find(user.id).profile
#messages = User.find(#profile.user_id).messages
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #messages }
end
end
My profile_messages.html.erb template:
<div id="tabs-2">
<% for message in #user.messagse %>
<div class="message">
</div>
<% end %>
</div>
Here is my routes.rb:
match "/profiles/profile_messages" => "profiles#profile_messages"
resources :profiles do
get :profile_messages, :on => :collection
end
My jQuery in application.js:
$(function() {
$( "#tabs" ).tabs({
ajaxOptions: {
error: function( xhr, status, index, anchor ) {
$( anchor.hash ).html(
"There was an error loading this tab. Please try again." );
}
}
});
});
I also have profile_messages.js.erb:
$( "#tabs" ).html( "<%= escape_javascript( render(#user.messages) ) %>" );
Any ideas on what's going on?
UPDATE: I got the layout to disappear by inserting the following into my profile_messages
def profile_messages
#profile = User.find(user.id).profile
#messages = User.find(#profile.user_id).messages
respond_to do |format|
format.html { render :layout => nil }
format.xml { render :xml => #messages }
end
end
The problem is in your controller. A few things about the profile_messages action:
def profile_messages
#profile = User.find(user.id).profile
#messages = User.find(#profile.user_id).messages
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #messages }
end
end
1) where is user.id coming from? You should be sending some parameters with the ajax request, so unless 'user' is a protected method in your controller, you'll need to supply the find method with params[:user_id] or something similar.
2) Use render :layout => false to fix the template issue.
3) As a side note, your first two lines are all over the place. It would be easier (and faster) to do this:
#user = User.includes(:messages, :profile).find(params[:user_id])
#messages = #user.messages # already in memory
#profile = #user.profile # already in memory