Rails 3 jQuery UI Tabs issue loading with Ajax - ruby-on-rails-3

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

Related

No route matches {:action=>"show", :controller=>"restaurants"}

If I want to go with my home page clicking on the map localhost:3000/maps gets out this error No route matches {:action=>"show", :controller=>"restaurants"}
controllers/maps_controller.rb
def index
#maps = Map.all
#json = Map.all.to_gmaps4rails do |map, marker|
marker.infowindow info_for_restaurant(map.restaurant)
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #maps }
end
end
def show
#map = Map.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #map }
end
end
private
def info_for_restaurant(restaurant)
link_to restaurant_path do
content_tag("h2") do
restaurant.name
end
end
end
routes.rb
resources :restaurants
resources :maps
This is answer for my question:
controllers/maps_controller.rb
def index
#maps = Map.all
#json = Map.all.to_gmaps4rails do |map, marker|
marker.infowindow render_to_string(:partial => "/maps/maps_link",
:layout => false, :locals => { :map => map})
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #maps }
end
end
views/maps/_maps_link.html.erb
<div class="map-link">
<h2><%= link_to map.restaurant.title, map.restaurant %></h2>
</div>
You referred to restaurant_path within info_for_restaurant, which is part of MapsController. Rails met error here.
You need to either define the restaurant_path in restaurant controller, or comment out this function in maps controller at this moment.
Your approach is wrong in several levels. Let's work on them, one at a time:
1) Your call to the route helper is wrong:
restaurant_path is the route helper for a show action. A show action needs an id parameter to be valid. Your call is missing a parameter.
So, your code must be something like this:
def info_for_restaurant(restaurant)
link_to restaurant_path(restaurant) do
content_tag("h2") do
restaurant.name
end
end
end
To see the parameters needed for each action, you can run rake routes on the console.
However, this does not solve the problem, as you're also:
2) Calling view helpers from your controller
link_to and content_tag are view helper methods, and you don't want to bother your controller with view issues. So, the best way to solve this problem is to move your info_for_restaurant method to a helper, and call it from a view instead.
So, now, your controller will not assign anything to #json, and the last line of your view will look like this:
<%= gmaps4rails #maps.to_gmaps4rails {|map, marker| marker.infowindow info_for_restaurant(map.restaurant) } %>

Ability to store Name/Email in a session

I have a form that I want a user to put in their name and email, which get stored in a session. They can then post text in a chat box.
In my view, to create the initial session:
<%= simple_form_for(#comments, :url => guest_login_order_path(#order)) do |f| %>
<input name="comment[new_user_comment_name]" />
<input name="comment[new_user_comment_email]" />
<%= f.button :submit, :value => 'Guest Signin', :class => '' %>
<% end %>
This goes to my controller:
def guest_login
#order = Order.where(:public_hash => params[:public_hash]).first
session[:new_user_account] = params[:new_user]
respond_to do |format|
if session[:new_user_account]
format.html { redirect_to #order, notice: 'Your account has been created.' }
format.json { render json: #order, status: :created, location: #order }
else
format.html { render action: "invoice" }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
The params get passed correctly but I'm not quite sure if the cookie is being created. Is there way to specify a name so I can see if it was created? Also in the view, would I have a conditional then to see if there is a session present?
Rails creates a session for you so you don't need to check if it's present. If you'd like to easily retrieve the user from the session you can create a helper method in your application controller:
class ApplicationController < ActionController::Base
def current_user
#current_user ||= session[:new_user_account]
end
helper_method :current_user
end
This method will be available to other controllers and views in your app.

Passing an object through a link_to command to be referenced in the model#new page

I'm creating a basic loyalty card application, with model Merchant and Loyaltycard. In the merchant#show view I have this line
<%=link_to 'New Loyalty card', new_loyaltycard_path(:merchant_id=>1) %>
I'm trying to pass the merchant ID to the loyaltycard#new view so it will be automatically selected as the merchant for that card. In loyaltycard#_form (which gets called by loyaltycard#new) I have the lines
<%if #merchant%>
<%= f.hidden_field :merchant_id, :value => #merchant.id %>
<%else%>
<div class="field">
<%= f.label :merchant_id %><br />
<%= f.text_field :merchant_id %>
</div>
<%end%>
But I keep getting and error that says can't call id for class Nil. Is there a better way of doing this?
Here is the controller code for loyaltycard
def new
#loyaltycard = Loyaltycard.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #loyaltycard }
end
end
# GET /loyaltycards/1/edit
def edit
#loyaltycard = Loyaltycard.find(params[:id])
end
# POST /loyaltycards
# POST /loyaltycards.json
def create
#loyaltycard = Loyaltycard.new(params[:loyaltycard])
respond_to do |format|
if #loyaltycard.save
format.html { redirect_to #loyaltycard, notice: 'Loyaltycard was successfully created.' }
format.json { render json: #loyaltycard, status: :created, location: #loyaltycard }
else
format.html { render action: "new" }
format.json { render json: #loyaltycard.errors, status: :unprocessable_entity }
end
end
end
The error is
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
What you need to do in your new action is using the params[:merchant_id] to look up and set #merchant
#merchant = Merchant.find(params[:merchant_id])
Then your code should work, without that, #merchant is nil, and you can't call the method :id on nil
You're not setting variable #merchant anywhere in your controller, but you use it the view.

Rendering a like/unlike button in rails with jQuery

I'm using jquery to render a like button on a story. I have two models story and like
Here's the likes controller code:
def create
#like = Like.new(params[:like])
#story = Story.find(params[:story])
#like.story = #story
if #like.save
respond_to do |format|
format.html
format.js
end
end
end
def destroy
#like = Like.find(params[:id])
##story = #like.story
#like.destroy
respond_to do |format|
format.html { redirect_to stories_url }
format.js
format.json { head :ok }
end
end
This is the button partial (stories/like_button):
<% unless user_likes_story?(#story, current_user) %>
<%= button_to 'like', "/likes?story=#{#story.id}", :id => 'like_button', :remote => true %>
<% else %>
<%= button_to 'liked', #liked, :class => 'like_button unlike', :id => 'unlike_button', :remote => true, method: :delete %>
<% end %>
The problem is that my create.js.erb, when rendering the 'unlike' button, doesn't properly load the #liked instance variable, because it's being set in the #show action of the stories controller before the user has liked the story, so I can't figure out how or where to set it so the JS will render the unlike properly. I'm probably making this harder than it has to be, but...
create.js.erb
$('.button_to').replaceWith('<%=j render 'stories/like_button' %>');
$('#story_likes_count').replaceWith('<%=j render 'stories/likes_count' %>');
Here's how I tried setting #liked, in stories#show
def show
#like = Like.new
#story = Story.find(params[:id])
if current_user
#liked = Like.find_by_user_id_and_story_id(current_user,#story)
end
respond_to do |format|
format.html # show.html.erb
format.json { render json: #story }
end
end
Any idea how to do this properly? Should I just move the partial out of the stories folder?
The solution was pretty simple. In the controller, doing this:
format.js {#liked = #like}
Passes the variable and makes it available to the partial when it's rendered.

Create and edit multiple records of the same model

I'm quite new to Rails and to this Q&A website! So hello everyone, I'm a French Rails tester. I have cross posted this question to Railsforum too, to have a better chance on getting an answer :) (http://railsforum.com/viewtopic.php?id=44238)
I need help on something. It seems simple, but in my opinion, not well documented (I browsed the web for 3 days without finding a clean answer. Some partial solutions here, but not a complete and clean one for a newbie!)
I want to add some actions to a default scaffolded controller to handle creation and modification of multiple records in the same form.
rails generate scaffold Item title:string
This is the sample scaffolded code:
app/controllers/items_controller.rb
class ItemsController < ApplicationController
# GET /items
# GET /items.xml
def index
#items = Item.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #items }
end
end
# GET /items/1
# GET /items/1.xml
def show
#item = Item.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #item }
end
end
# GET /items/new
# GET /items/new.xml
def new
#item = Item.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #item }
end
end
# GET /items/1/edit
def edit
#item = Item.find(params[:id])
end
# POST /items
# POST /items.xml
def create
#item = Item.new(params[:item])
respond_to do |format|
if #item.save
format.html { redirect_to(#item, :notice => 'Item was successfully created.') }
format.xml { render :xml => #item, :status => :created, :location => #item }
else
format.html { render :action => "new" }
format.xml { render :xml => #item.errors, :status => :unprocessable_entity }
end
end
end
# PUT /items/1
# PUT /items/1.xml
def update
#item = Item.find(params[:id])
respond_to do |format|
if #item.update_attributes(params[:item])
format.html { redirect_to(#item, :notice => 'Item was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #item.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.xml
def destroy
#item = Item.find(params[:id])
#item.destroy
respond_to do |format|
format.html { redirect_to(items_url) }
format.xml { head :ok }
end
end
end
app/views/items/new.html.erb
<h1>New item</h1>
<%= render 'form' %>
<%= link_to 'Back', items_path %>
app/views/items/edit.html.erb
<h1>Editing item</h1>
<%= render 'form' %>
<%= link_to 'Show', #item %> |
<%= link_to 'Back', items_path %>
app/views/items/_form.html.erb
<%= form_for(#item) do |f| %>
<% if #item.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#item.errors.count, "error") %> prohibited this item from being saved:</h2>
<ul>
<% #item.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In my opinion, I need to add 4 methods to my Item controller:
new_multiple : to initialize the new
multiple form view
create_multiple :
to handle results from the new
multiple form view
edit_mulitple : to
initialize the edit multiple form
view
update_mulitple : to handle
results from the edit multiple form
view
Then, I need to create 2 new views:
new_multiple.html.erb with code for a multiple record (5 in the same time) creation form
edit_mulitple.html.erb with code for a multiple record (5 in the same time) edition form
and maybe _partials to avoid DRY stuff...
Anyone want to help me write these 4 actions and 2 views? I would really appreciate that.
Thanks! :)
Note : In my application items are children of parentItems but I DON'T WANT to use nested_form to create items in parentItems forms like in railscast 196 and 197.