Rails 3 and Ajax confusion - ajax

In short, I don't understand ajax with rails. I did this tutorial a little while ago and I can get it to work. No problems. The problems seem arise when I have more than one model.
For example, if I have a model "cats", I use the tutorial to implement some ajax, works nicely - each time I add a new cat to the list, it appears at the top without reloading the page. Then I add a "dogs" model, and I render the _dog.html.erb file in the cats index and call on it with something like #dogs.each do |dog| etc.
Now I need to implement the ajax for the dogs, but do I put the ajax files into create.js.erb in the dogs folder or in the cats create.js.html folder? I've tried both, no success. The first model, in this example cats, will continue to work, but the others don't. I know that its half working because the page doesn't reload when I hit enter, but nothing is generated either. I've checked the id's, all correct.
Is there anything else I should be looking for? My logic says that if i'm in the cats index and rendering something from _dog.html.erb, I should put all the create ajax in the cats create.js.html folder….
Help is more than appreciated.
Also, just as a small second question, I read another tutorial and it advised me to delete everything in the public/javascripts folder except "application.js", which in my case is blank. I haven't because ajax is working, just not for the other models. Should I take the tutorials advise?
Thanks again.
Update
This is the code from "show" in the cats controller.
#dog = Dog.new
respond_to do |format|
format.html
end
Update 2
Ok, so "Cats" is really "Games", and "Dogs" is really "Features". I used the cats and dogs examples because I thought in theory it would be easier, sorry if it made it more confusing :).
The code - the ajax for creating games in the games index is working, but the ajax for creating features in the games show is not. The games show is where I want to create new features using ajax. the features are created but only viewable after a page reload.
class GamesController < ApplicationController
def index
#games = Game.paginate(:page => params[:page], :per_page => 10)
#game = Game.new
respond_to do |format|
format.html
end
end
def show
#user = User.find(params[:id])
#gameid = Game.find(params[:id])
#features = Feature.paginate(:page => params[:page], :per_page => 8, :conditions => {:game_id => #gameid})
#feature = Feature.new
respond_to do |format|
format.html
end
end
def create
#game = Game.new(params[:game])
respond_to do |format|
if #game.save
format.html { redirect_to(games_url,
:notice => 'game was successfully created.') }
format.js
else
format.html { redirect_to(games_url) }
end
end
end
def destroy
#game = Game.find(params[:id])
#game.destroy
respond_to do |format|
format.html { redirect_to(games_url) }
format.js
end
end
end
class FeaturesController < ApplicationController
def index
#features = Feature.all
#feature = Feature.new
respond_to do |format|
format.html
end
end
def show
end
def create
#feature = Feature.new(params[:feature])
respond_to do |format|
if #feature.save
format.html { redirect_to(features_url,
:notice => 'feature was successfully created.') }
format.js
else
format.html { redirect_to(features_url) }
end
end
end
def destroy
#feature = Feature.find(params[:id])
#feature.destroy
respond_to do |format|
format.html { redirect_to(features_url) }
format.js
end
end
end
(features/create.js.erb)
$('#features').prepend('<%= escape_javascript(render(#feature)) %>');
$('#features > li:first').effect('highlight', {}, 3000);
$('#features_form > form')[0].reset();
(games/create.js.erb)
$('#games').prepend('<%= escape_javascript(render(#game)) %>');
$('#games > li:first').effect('highlight', {}, 3000);
$('#game_form > form')[0].reset();
(games/index)
<h1>Games</h1>
<table>
<tr>
<td class="main">
<ul id="games">
<% #games.each do |game| %>
<%= render 'game', :game => game %>
<% end %>
</ul>
<% if signed_in? %>
<div id="game_form">
<%= render 'form' %>
</div>
<% else %>
<% end %>
</td>
<td class="sidebar">
</td>
</tr>
</table>
(games/show)
<h1>Features</h1>
<table>
<tr>
<td class="main">
<h2>Features</h2>
<div id="features_form">
<%= render 'features/form' %>
</div>
<ul id="features" style="margin:0;padding:0;">
<% #features.each do |feature| %>
<%= render 'features/feature', :feature => feature %>
<% end %>
<%= will_paginate #features, :class => 'pagination' %>
</ul>
</td>
<td class="sidebar">
</td>
</tr>
</table>

Ok, I got it to work. All that was missing was format.js under the format.html in show in the games controller. Like this:
def show
#user = User.find(params[:id])
#gameid = Game.find(params[:id])
#features = Feature.paginate(:page => params[:page], :per_page => 8, :conditions => {:game_id => #gameid})
#feature = Feature.new
respond_to do |format|
format.html
format.js
end
end
I guess the strange thing is that games didn't need this to execute ajax...
Cheers guys for the help

Related

Rails: Submitting an array of child elements

I'm trying to submit a form which is supposed to have an array of child elements. I'm not sure if I have it correctly. Can somebody help me refactor?
I have a couple of models user and item. A userhas_many :items.
The form that sends the information for user and items look like the following -
<%= form_for(#user) do |f| %>
<% f.text_field :name %>
<% f.fields_for :items do |item| %>
<% item.text_field :name %>
<% item.text_field :price %>
<% end %>
<% end %>
I have the following in my controller -
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
#items = #user.items.build(item_params)
if #items.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
end
format.html { redirect_to #user, notice: 'User was successfully created. But there was a problem saving the items.' }
else
format.html { render action: 'new' }
format.json { render json: #userd.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:name)
end
def item_params
params.require(:user).require(:item).permit(:name, :price)
end
When I save the user, only 1 record of items get saved, meaning - the data isn't being passed as an array of objects. How do I get this to work?
It looks like right now you are only ever telling Rails to build one item object. Your form is passing up the two parameters for an item, and in your controller you call build once, so #items is only ever set equal to the single Item returned by build. Unless their are hidden parts of your form you aren't showing, it looks like you're only setting one set of options for a user's items. If your goal is to have an array of many items with identical parameters, the fastest fix would be to just do this within the logic of your create action. There are many ways you could implement that (here is one simple way):
#items = []
x.times { #items << #user.items.build(item_params) }
If you're looking to send a request from the form with multiple unique items, you'll have to add more fields to your form, since currently you are only sending one set of parameters.
There are few corrections to be made in your code.
In your users_controller
def new
#user = User.new
3.times do #this will generate three records of items
#user.items.build
end
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #userd.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:name,items_attributes: [:name,price])
end

How to use last created forms values for new form?

I have the follow models:
User
has_many :armies
Army
belongs_to :user
My controller with the added current_user:
class ArmiesController < ApplicationController
before_filter :authenticate_user!
def new
#army = Army.new
end
def create
#army = current_user.armies.new(params[:army])
respond_to do |format|
if #army.save
format.html { redirect_to new_army_path, :notice => "New army added" }
else
format.html { render :new }
end
end
end
end
I want to use my last created forms value for the new one. We'll use my strength field as an example:
<%= form_for #army do |f| %>
<%= f.label :strength, "Army Strength" %>
<%= f.text_field :amount %>
<%= f.submit "Create" %>
<% end %>
How can I save the value that the user input's in the strength field so it remains on the form after the last form is created?
EDIT:
def new
#army = Army.new(strength: session[:last_army_strength],
type_id: session[:last_type])
end
def create
#army = current_user.armies.new(params[:army])
session[:last_army_strength] = params[:army][:strength]
session[:last_type] = params[:army][:type_id]
respond_to do |format|
if #army.save
format.html { redirect_to new_army_path, :notice => "New army added" }
else
format.html { render :new }
end
end
end
end
I think this should work:
class ArmiesController < ApplicationController
before_filter :authenticate_user!
def new
#army = Army.new(strength: session[:last_army_strength])
end
def create
#army = current_user.armies.new(params[:army])
session[:last_army_strength] = params[:army][:strength]
respond_to do |format|
if #army.save
format.html { redirect_to new_army_path, :notice => "New army added" }
else
format.html { render :new }
end
end
end
end

Rails 3 -rendering partials and error "undefined local variable or method"

I have a photos in gallery (PhotosController) and I wanna add to every photo a comments. Into the statement of photos I added a partial for rendering comments + form for adding new comment.
My problem is, that when I send the form with a new comment, so I'll get the rendering error:
**NameError (undefined local variable or method `photo' for #<CommentsController:0x00000100ce0ad0>)**:
This is how looks my code:
views/photos/index.html.erb
<%= render #photos %>
views/photos/_photo.html.erb
<div><%=image_tag photo.photo.url(:thumb)%></div>
<div class="comments_to_photo">
<%= render :partial => 'photos/photo_comments', :locals => { :photo => photo }%>
</div>
photos/photo_comments
<%photo.comments.each do |cmnt|%>
<div><%=cmnt.comment%></div>
<%end%>
<%=form_tag comment_path, :remote => true do %>
<div><%=text_area_tag 'comment[comment]'%></div>
<%=submit_tag%>
<%end%>
controllers/CommentsController
def create
#comment = Comment.new(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.js {
render :partial => '/photos/photo_comments', :locals => { :photo => photo } do |page|; page << "$(this).html('abcde');" end
}
else
format.html { render action: "new" }
format.js
end
end
end
I would like to refresh the form and comments statement in the photo, where was added a comment. Could anyone help me, please, how to avoid the error above?
Thank you in advance
EDIT: I added for refresh comments through AJAX the file _photo_comments.js.erb:
$('#photo_comment').html("<%= escape_javascript(render('photos/photo_comments')) %>");
And I get the error
ActionView::Template::Error (stack level too deep):
activesupport (3.2.1) lib/active_support/notifications/instrumenter.rb:23
with tens of this line:
Rendered photos/_photo_comments.js.erb (562.2ms)
and the last one
Completed 500 Internal Server Error in 580ms
What's wrong with rendering? I can't render partial html file from partial JS file?
In your controller you have:
:locals => { :photo => photo }
but the variable photo doesn't exist there. It should be:
:locals => { :photo => #comment.photo }
image_tag photo.photo.url(:thumb) <- Is it what you want to have photo.photo ?

Rails 3 render partial outside view?

I am working on a multisite for a client for a skateboarding website. So far everything is great but I am starting to get stuck on the whole partial thing. I have a site and site has_many :albums(Album also belongs to site) but when I try to render albums from a site on the sites homepage i get undefined method `model_name' for NilClass:Class?
I have am trying to render albums/_album.html.erb on the sites/show page to display a site latest's album on the homepage of the site.
Albums Controller
class AlbumsController < ApplicationController
def index
#albums = Album.all
end
def show
#album = Album.find(params[:id])
end
def new
#album = Album.new
end
def edit
#album = Album.find(params[:id])
end
def create
#album = current_site.albums.build(params[:album])
if #album.save
redirect_to albums_path, :notice => 'Album was successfully created.'
end
end
def update
#album = Album.find(params[:id])
if #album.update_attributes(params[:album])
redirect_to album_path(#album), :notice => 'Album was successfully updated.'
end
end
def destroy
#album = Album.find(params[:id])
#album.destroy
end
end
Sites Controller
class SitesController < ApplicationController
def index
#sites = Site.all
end
def show
#site = Site.find_by_subdomain!(request.subdomain)
end
def new
#site = Site.new
end
def edit
#site = Site.find(params[:id])
end
def create
#site = Site.new(params[:site])
if #site.save
redirect_to #site, :notice => 'Signed up!'
end
end
def update
#site = Site.find(params[:id])
if #site.update_attributes(params[:site])
redirect_to #site, :notice => 'Site was successfully updated.'
end
end
def destroy
#site = Site.find(params[:id])
#site.destroy
end
end
Site Show.html
<p id="notice"><%= notice %></p>
<p>
<b>First name:</b>
<%= #site.first_name %>
</p>
<p>
<b>Last name:</b>
<%= #site.last_name %>
</p>
<p>
<b>Subdomain:</b>
<%= #site.subdomain %>
</p>
<%= render :partial => 'albums/album'%>
<%= link_to 'Edit', edit_site_path(#site) %> |
<%= link_to 'Back', sites_path %>
Albums/_album.html.erb
<%= div_for #album do %>
<h2><%= #album.title %></h2>
<%= image_tag #album.photo.url(:small) %>
<% end %>
Am I missing something in my albums controller?
In your show.html, you need to pass in the collection of albums to the render method
<%= render :partial => 'albums/album', :collection => #site.albums %>
Within the _album.html.erb partial, you need to reference the album attribute as a local attribute, like so
<%= div_for album do %>
<h2><%= album.title %></h2>
...
You can read more about partials here 3.4.5 Rendering Collections

RoutingError when using jQuery UI tabs with ajax

I'm getting ActionController::RoutingError in Profiles#show when I click a link to render a layout as part of my implementation of jQuery UI tabs. Here's my link_to:
<%= link_to "Messages", :controller => 'profiles', :action => 'profile_messages', :remote => true %>
My ProfilesController:
def profile_messages
#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 erb layout:
<div id="tabs-2">
<% for message in #user.messages %>
<div class="message-1">
</div>
<% end %>
</div><!-- end messages -->
Routes.rb:
resources :messages do
get "messages/profile" => :profile_messages
resources :responses
end
What I want to happen is: when you click the link created by my link_to, the layout in profile_messages.html.erb shows and loads the messages in that specific layout. What's going on here?
UPDATE: Adding the new line in Routes.rb gives me a new route:
message_messages_profile GET /messages/:message_id/messages/profile(.:format) {:action=>"profile_messages", :controller=>"messages"}
So I tried this in my Profiles show.html.erb I put:
<li><%= link_to "Messages", message_messages_profile_path, :remote => true %></li>
This gives me a RoutingError in Profiles#show -- No route matches {:action=>"profile_messages", :controller=>"messages"}. Even when I add the following into my MessagesController:
def profile_messages
#message = #user.messages.find(params[:user_id])
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #messages }
end
end
get "messages/profile" => "messages#profile_messages", :as => profile_messages
resource :messages do
resource :responses
end
You don't have a route for that controller action. Rails doesn't map ":controller/:action/:id" by default any more. You can also just enable that route if you want. You could be able to reference this via profile_messages_path.
It's assuming 'show' is actually an id for messages here I think. The default routes for a resource are listed here: http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions. Make sure you list your routes first!
resource :messages do
collection do
get :profile_messages
end
end
in your view
<li><%= link_to "Messages", "/messages/profile_messages", :remote => true %></li>
Thanks to the combined efforts of folks here on SO I was able to get this to work. Check out these questions for more code:
Exclude application layout in Rails 3 div
Rails 3 jQuery UI Tabs issue loading with Ajax

Resources