Rails 3 render partial outside view? - ruby

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

Related

render :new is not working anymore when I'm using services

I'm trying to learn about services in Rails in order to avoid fat controllers.
Here a tried a simple product review creation
class ProductReviewsController < ApplicationController
before_action :set_product, only: :create
def new
#product_review = ProductReview.new
#product = Product.find(params[:product_id]) end
def create
if AddReviewService.call(product_review_params, #product)
redirect_to product_path(#product)
else
render :new
end
end
private
def set_product
#product = Product.find(params[:product_id]) end
def product_review_params
params.require(:product_review).permit(:content, :rating) end end
The thing is that in the case of wrong parameters for the review the render :new generates the following error :
screenshot of error received
Showing /home/miklw/code/michaelwautier/multitenant_app/app/views/product_reviews/new.html.erb where line #3 raised:
undefined method 'model_name' for nil:NilClass
Extracted source (around line #3):
1 <h1>New review for <%= #product.name %></h1>
2
3 <%= simple_form_for [#product, #product_review] do |f| %>
4 <%= f.input :content %>
5 <%= f.input :rating %>
6 <%= f.button :submit %>
Rails.root: /home/miklw/code/michaelwautier/multitenant_app
Application Trace | Framework Trace | Full Trace
app/views/product_reviews/new.html.erb:3:in `_app_views_product_reviews_new_html_erb__802305224391576972_70155240081100'
app/controllers/product_reviews_controller.rb:14:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"Z7YeYvXKKr7uYhANlevZ4H8U00p9givKzXzfue4pNFk0jE2DtTNY7Eacqati+V8IihSofLc2WPa4ZBzR2o0v5w==",
"product_review"=>{"content"=>"te", "rating"=>"9"},
"commit"=>"Create Product review",
"product_id"=>"4"}
Toggle session dump
Toggle env dump
Response
Headers:
None
In the error page console, if I type #product, I get the expected product object, but #product_review is nil.
BUT, if I use the regular way (see below), the form gets re-render as it should, with the notice message of the form
class ProductReviewsController < ApplicationController
before_action :set_product, only: :create
def new
#product_review = ProductReview.new
#product = Product.find(params[:product_id])
end
def create
#product_review = ProductReview.new(product_review_params)
#product_review.product = #product
if #product_review.save
redirect_to product_path(#product)
else
render :new
end
end
private
def set_product
#product = Product.find(params[:product_id])
end
def product_review_params
params.require(:product_review).permit(:content, :rating)
end
end
Any idea what could cause this issue ?
EDIT : Here is the service I call :
class AddReviewService < ApplicationService
attr_reader :content, :rating
def initialize(params, product)
#content = params[:content]
#rating = params[:rating]
#product = product
end
def call
review = ProductReview.new(content: #content, rating: #rating)
review.product = #product
return true if review.save
return false
end
end
EDIT 2 : returning the review when saved
def call
review = ProductReview.new(content: #content, rating: #rating)
review.product = #product
return review if review.save
return false
end

Missing Params on Post in Rails?

I'm learning Ruby on Rails at the moment and we're making a blog app to learn about crud actions and such and I'm stuck on this create method in my controller not working as it does in the course. I'm having trouble the create method in this controller:
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
def new
end
def create
#article = Article.new(params.require(:article).permit(:title, :description))
#article.save
redirect_to #article
end
end
I get this error when trying to create an article:
ActionController::ParameterMissing in ArticlesController#create
param is missing or the value is empty: article
It seems to be getting hung up on the first line of the create method but I'm not sure why it doesn't think there's an article... Here's my new article view as well for further reference:
<h1>Create a new Article</h1>
<%= form_with scope: #article, url: articles_path, local: true do |f| %>
<p>
<%= f.label :title %><br/>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br/>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Check whether your parameters coming under hash with key article like this -
{"article"=>{params}}
Also initiate Article object in new action.
You can redefine the params to permit like this:
in controller new method create object
#article = Article.new
and in form HTML add one more option use method: "post"

Ajax and Ruby on Rails with local variable?

I really don't get how to use Ajax with Ruby on Rails. I must be missing something simple.
What I want to do is to ask the user to select a date, and then make a table of documents appear, but only with the selected date (Date is an attribute of Document).
My idea is to create a local variable witch is not in my database, store the selected date in it, and then create a loop in my view saying for example #document.where(:date = date).each...
In app/controllers/documents_controller.rb, I have :
class DocumentsController < ApplicationController
def information
#documents = Document.all
#date = params[:date]
respond_to do |format|
format.html # index.html.erb
format.js{}
format.json { render json: #documents}
end
end
end
And in app/views/documents/_information.js.erb, I have:
<%= form_tag(document, :remote => true) do %>
<%= label_tag(:date, "The selected date is:") %>
<%= text_field_tag(:date) %>
<%= submit_tag %>
<% end %>
In the end, I have a field where the user puts his date, but the submit button doesn't do anything.
What do I miss ?
As discussed you need to change the flow of your app.Lets go through steps one by one
a. create your input field where you are selecting your date field. You already have your form for that
<%= form_tag(you_path_for_information_method, :remote => true) do %>
<%= label_tag(:date, "The selected date is:") %>
<%= text_field_tag(:date) %>
<%= label_tag(:portfolio, "Add portfolio") %>
<%= text_field_tag(:portfolio) %>
<%= submit_tag %>
<% end %>
In controller
def information
#documents = Document.all
#date = params[:date]
#portfolio = Portfolio.find(params[:portfolio])
respond_to do |format|
format.js{}
end
end
In your information.js.erb you can have:
$("#some_id_of_parent").html("<%=j render partial: "your_partial", locals: {portfolio: #portfolio} %>")

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 and Ajax confusion

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

Resources