NoMethodError in PagesController#home - ruby-on-rails

I'm working through the Rails Tutorial Chapter 12, and get the following error on the Home/Main page when user is signed out (signed in is OK):
I'm a newbie to Rails so please be explicit in your response! Many thanks..
NoMethodError in PagesController#home
undefined method `feed' for nil:NilClass
Rails.root: /Users/fkhalid2008/Documents/First-app
Application Trace | Framework Trace | Full Trace
app/controllers/pages_controller.rb:6:in `home'
Pages Controller
class PagesController < ApplicationController
def home
#title = "Home"
#post = Post.new if signed_in?
#feed_items = current_user.feed.paginate(:page => params[:page])
end
def contact
#title = "Contact"
end
def about
#title = "About Us"
end
end
Home Page View (/app/views/pages/home.html.erb)
<% if signed_in? %>
<table class="front" summary="For signed-in users">
<tr>
<td class="main">
<h1 class="post">What's up?</h1>
<%= render 'shared/post_form' %>
<%= render 'shared/feed' %>
</td>
<td class="sidebar round">
<%= render 'shared/user_info' %>
</td>
</tr>
</table>
<% else %>
<h1>Palazzo Valencia</h1>
<p>
This is the home page for the
Palazzo Valencia
sample application.
</p>
<%= link_to "Sign up now!", signup_path, :class => "signup_button round" %>
<% end %>
Feed Partial
<% unless #feed_items.empty? %>
<table class="posts" summary="User posts">
<%= render :partial => 'shared/feed_item', :collection => #feed_items %>
</table>
<%= will_paginate #feed_items %>
<% end %>
Feed_item Partial
<tr>
<td class="gravatar">
<%= link_to gravatar_for(feed_item.user), feed_item.user %>
</td>
<td class="post">
<span class="user">
<%= link_to feed_item.user.name, feed_item.user %>
</span>
<span class="content"><%= feed_item.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(feed_item.created_at) %> ago.
</span>
</td>
<% if current_user?(feed_item.user) %>
<td>
<%= link_to "delete", feed_item, :method => :delete,
:confirm => "You sure?",
:title => feed_item.content %>
</td>
<% end %>
</tr>

The user is not signed in. Therefore, the current_user method is returning nil, and ruby can't find the feed method.
You could change the code to this:
#title = "Home"
if signed_in?
#post = Post.new
#feed_items = current_user.feed.paginate(:page => params[:page])
end
Now, the new post and the feed items will only be retrieved when the user is signed in.

app/controllers/static_pages_controller.rb
def home
if logged_in?
#micropost = current_user.microposts.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
end

Related

Form_tag routing error after unsuccessful submit

I have an index page with a partial form to submit new records to Package model. I keep this form in the index page, so the user doesn't need to leave the page when repeating this action, several times.
In the same page I have a form_tag fir multiple updates for the same controller, namely packages_controller.
Everything works fine, except the following: when hit the update button, going to the form BUT instead of submitting I go back (with the browser) and try to select other records to be updated then I have a routing error:
Routing Error
No route matches [PUT] "/projects/47/orderlines/18/packages"
My index page looks like this:
<% if current_user %>
<%= render "packages/form" %>
<% end %>
<% if #packages.count >= 1 %>
<table class="table table-striped">
<thead>
<tr>
<th> <input type="checkbox" id="selectAll" value="selectAll"></th>
<th>Packed </th>
<th>#No.</th>
<th>Type</th>
<th>Gross weight</th>
<th>Length</th>
<th>Width</th>
<th>Height</th>
<th></th>
<th>Container</th>
</tr>
</thead>
<%= form_tag edit_multiple_project_orderline_packages_path, method: :get do %>
<tbody>
<% for package in #packages %>
<% if package.packed== true %>
<% #label_type="success" %>
<% else %>
<% #label_type="default" %>
<% end %>
<tr>
<td><%= check_box_tag "package_ids[]", package.id %></td>
<td><span class="label label-<%= #label_type %>"><% if package.packed==true %>Packed<% else %>Unpacked<% end %></span></td>
<td><%= package.package_no %></td>
<td><%= package.package_type %></td>
<td><%= package.gross_weight %></td>
<td><%= package.length %></td>
<td><%= package.width %></td>
<td><%= package.height %></td>
<% if #orderline.packages.count >= 1 %>
<td><%= link_to 'Delete', [package.orderline.project, package.orderline, package],
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
<td><%= #containers.find(package.container_id).container_id if package.packed %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
<%= submit_tag "Add to container", class: "btn btn-primary" %>
<% end %>
<br />
<%= will_paginate %>
<br>
And the multiple_edit form
<div class="col-sm-4">
<%= form_tag update_multiple_project_orderline_packages_path, method: :put do %>
<ul>
<% #packages.each do |package| %>
<li>
<%= hidden_field_tag "package_ids[]", package.id %>
<%= package.package_no %>
<%= package.container_id %>
<% package.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</li>
<% end %>
</ul>
<%= fields_for :package do |f| %>
<div class="field">
<%= f.label :package_no %><br />
<%= f.text_field :package_no, :class => "form-control" %>
</div>
<br />
<div class="field">
<%= f.label :container_id %><br />
<%= select_tag 'package[container_id]', options_from_collection_for_select(#project.containers, 'id', 'container_id', default_blank: true), prompt: "- Select container -", :class => "form-control" %>
</div>
<br />
<div class="field">
<%= f.label :packed %><br />
<%= f.select :packed, [["Packed", true], ["Unpacked", false]],{ prompt: "- Packing -"},{ :class => "form-control" } %>
</div>
<% end %>
<div class="actions">
<br />
<%= submit_tag "Update", :class => "btn btn-primary" %>
</div>
<% end %>
</div>
And the packages controller edit_multiple actions:
def edit_multiple
#project = Project.find(params[:project_id])
#packages = Package.find(params[:package_ids])
end
def update_multiple
#packages = Package.find(params[:package_ids])
#packages.reject! do |package|
package.update_attributes(package_params.reject { |k,v| v.blank? })
end
if #packages.empty?
redirect_to project_orderline_packages_url
else
#package = Package.new(package_params)
render "edit_multiple"
end
end
packages_controller create action:
def create
project = Project.find(params[:project_id])
orderline = project.orderlines.find(params[:orderline_id])
#package = orderline.packages.new(package_params)
#package.save
if #package.save
flash[:success] = "Package(s) was successfully added."
redirect_to :back
else
render 'new'
end
And my routes:
resources :projects do
resources :containers
resources :orderlines do
resources :packages do
collection do
put :packed
get :edit_multiple
put :update_multiple
end
end
end
end
I just added my routes here:
edit_multiple_project_orderline_packages_path GET /projects/:project_id/orderlines/:orderline_id/packages/edit_multiple(.:format)
packages#edit_multiple
update_multiple_project_orderline_packages_path PUT /projects/:project_id/orderlines/:orderline_id/packages/update_multiple(.:format)
packages#update_multiple
project_orderline_packages_path GET /projects/:project_id/orderlines/:orderline_id/packages(.:format)
packages#index
POST /projects/:project_id/orderlines/:orderline_id/packages(.:format)
packages#create
new_project_orderline_package_path GET /projects/:project_id/orderlines/:orderline_id/packages/new(.:format)
packages#new
edit_project_orderline_package_path GET /projects/:project_id/orderlines/:orderline_id/packages/:id/edit(.:format)
packages#edit
project_orderline_package_path GET /projects/:project_id/orderlines/:orderline_id/packages/:id(.:format)
packages#show
PATCH /projects/:project_id/orderlines/:orderline_id/packages/:id(.:format)
packages#update
PUT /projects/:project_id/orderlines/:orderline_id/packages/:id(.:format)
packages#update
DELETE /projects/:project_id/orderlines/:orderline_id/packages/:id(.:format)
your form_tag code is update_multiple_project_orderline_packages_path
I think it should be update_multiple_project_orderline_package_path(project_id, orderline_id, package_id)
I am not 100% sure with my statement above, because you gave scrambled Rails Routes, hard to read
and your form action seems goes to packages#edit_multiple controller
so paste your edit_multiple method, not create method
are you implementing your scenario above with javascript, or just plain HTML?

undefined method `total_pages' for #<Review:0x007fe460871f08>

The error output is:
undefined method `total_pages' for #<Review:0x007fe460871f08>
Movie#Show:
def show
#review = #movie.reviews.paginate(page: params[:page], per_page: 6).order('created_at DESC').build
end
I set #movie via before_filter.
My view:
<% if #movie.now_playing %>
<% if #movie.reviews.any? %>
<% #movie.reviews.each do |review| %>
<div id="each_review_container">
<span><%= link_to #movie.creator.name, user_path(#movie.creator) %> | </span>
<span id="time"><%= review.created_at.try(:strftime,'%b %d, %Y') %></span>
<p>Rating: <%= review.rating %>/10</p>
<p><%= review.content %></p>
</div>
<% end %>
<div class="digg_pagination"><%= will_paginate #review %></div>
<% else %>
<span id="review_message">No Reviews yet!</span>
<span id="add_new_review_link"><%= link_to 'Add New Review', new_movie_review_path(#movie) %></span>
<% end %>
<% else %>
<p id="review_message">You will be able to submit a review when the movie releases</p>
<% end %>
Restarted my server and I get the same error.
Been stuck on this for a while and would appreciate any assistance, thanks!
It looks like a bug, I think you want to get reviews not one review:
def show
#reviews = #movie.reviews.order('created_at DESC').paginate(page: params[:page], per_page: 6)
end
View:
<% if #movie.now_playing %>
<% if #reviews.any? %>
<% #reviews.each do |review| %>
<div id="each_review_container">
<span><%= link_to #movie.creator.name, user_path(#movie.creator) %> | </span>
<span id="time"><%= review.created_at.try(:strftime,'%b %d, %Y') %></span>
<p>Rating: <%= review.rating %>/10</p>
<p><%= review.content %></p>
</div>
<% end %>
<div class="digg_pagination"><%= will_paginate #reviews %></div>
<% else %>
<span id="review_message">No Reviews yet!</span>
<span id="add_new_review_link"><%= link_to 'Add New Review', new_movie_review_path(#movie) %></span>
<% end %>
<% else %>
<p id="review_message">You will be able to submit a review when the movie releases</p>
<% end %>
In Your view ,you are calling #movie.reviews
Why are you writing #movie.reviews in loop ?You should be using #review of action instead.It is firing query every time you call it.
#movie.reviews in your view is causing error here's guess,since it doesn't include pagination parameter and you are trying to pagination through it.

errors uploading a file "name cant be blank"

I am trying to add the option to upload and download files in my Rails application, but I keep getting this error when I try to upload my file:
name can't be blank
Here's my code:
newsletters_controller.rb:
class NewslettersController < ApplicationController
def index
#newsletters = Newsletter.all
end
def new
#newsletter = Newsletter.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #newsletter }
end
end
def create
#newsletter = Newsletter.new(newsletter_params)
if #newsletter.save
redirect_to newsletters_path, notice: "The newsletter #{#newsletter.name} has been uploaded."
else
render "new"
end
end
def destroy
#newsletter = Newsletter.find(params[:id])
#newsletter.destroy
redirect_to newsletters_path, notice: "The newsletter #{#newsletter.name} has been deleted."
end
private
def newsletter_params
params.require(:newsletter).permit(:newsletter, :attachment)
end
end
index.html.erb:
<% if !flash[:notice].blank? %>
<div class="alert alert-info">
<%= flash[:notice] %>
</div>
<% end %>
<br />
<%= link_to "New Newsletter", new_newsletter_path, class: "btn btn-primary" %>
<br />
<br />
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>Download Link</th>
<th> </th>
</tr>
</thead>
<tbody>
<% #newsletters.each do |newsletter| %>
<tr>
<td><%= newsletter.name %></td>
<td><%= link_to "Download Newsletter", newsletter.attachment_url %></td>
<td><%= button_to "Delete", newsletter, method: :delete, class: "btn btn-danger", confirm: "Are you sure that you wish to delete #{newsletter.name}?" %></td>
</tr>
<% end %>
</tbody>
</table>
new.html.erb:
<% if !#newsletter.errors.empty? %>
<div class="alert alert-error">
<ul>
<% #newsletter.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="well">
<%= form_for #newsletter, html: { multipart: true } do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :attachment %>
<%= f.file_field :attachment %>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
</div>
routes.rb:
resources :newsletters, only: [:index, :new, :create, :destroy]
root "newsletters#index"
get "newsletters/index"
get "newsletters/new"
get "newsletters/create"
get "newsletters/destroy"
change:
params.require(:newsletter).permit(:newsletter, :attachment)
to:
params.require(:newsletter).permit(:newsletter, :attachment, :name)
This way, the model will receive the name from the form and validation will succeed.

Destroying Sessions Issue Rails 4

I'm having problems destroying the session, the link doesn't seem to work, the URL changes in the address bar from /dashboard to /log_out but the page does not redirect to the log in page. I'm rather baffled at this.
Dashboard View:
<% if logged_in? %>
<% if request.env['mobvious.device_type'] == :mobile %>
<div class="container" style="width: 90%" >
<table>
<tr>
<td class="dash_cont">
<%= link_to "Logout", log_out_path %>
</td>
</tr>
<tr>
<td class="dash_cont">
<h1 class="form-signin-heading" >Welcome to your personal Twitter Manager!</h1>
<p>Use this site to keep track of your followers, see how many posts they've made and many more features!</p>
<p>It's a really cool site, check it out! It's free!</p><br/><br/>
</td>
</tr>
</table>
</div>
<% elsif request.env['mobvious.device_type'] == :desktop %>
<div class="container" style="width: 70%;" >
<table>
<tr>
<td class="dash_cont">
<%= link_to "Logout", log_out_path %>
</td>
</tr>
<tr>
<td class="dash_cont">
<h1 class="form-signin-heading" >Welcome to your personal Twitter Manager!</h1>
<p>Use this site to keep track of your followers, see how many posts they've made and many more features!</p>
<p>It's a really cool site, check it out! It's free!</p><br/><br/>
</td>
</tr>
</table>
</div>
<% end %>
<% else %>
<script type="text/javascript">
window.location.href="/" // put your correct path in a string here
</script>
<% end %>
Log In View:
<% if logged_in? %>
<script type="text/javascript">
window.location.href="/dashboard" // put your correct path in a string here
</script>
<% else %>
<% if request.env['mobvious.device_type'] == :mobile %>
<div class="container" style="width: 90%" >
<table>
<tr class="login-cont">
<td class="login-tcell">
<h1 class="form-signin-heading" >Log in</h1>
<%= form_tag sessions_path, class: "form-signin" do %>
<%= text_field_tag :email, params[:email], class: "form-control", autofocus: "", required: "", placeholder: "Email address" %>
<%= password_field_tag :password, nil, class: "form-control", required: "", placeholder: "Password" %></br>
<p class="button"><%= submit_tag "Log in", class: "btn btn-lg btn-primary btn-block" %></p>
<% end %>
<%= link_to "Register", "/sign_up" %>
<% if defined?(#error) %>
<div class="error">
<%= "*" + #error %>
</div>
<% end %>
<% if defined?(#notice) %>
<div class="error">
<%= "*" + #notice %>
</div>
<% end %>
</td>
</tr>
</table>
</div>
<% elsif request.env['mobvious.device_type'] == :desktop %>
<div class="container" style="width: 70%" >
<table>
<tr class="login-cont">
<td class="login-tcell">
<h1 class="form-signin-heading" >Log in</h1>
<%= form_tag sessions_path, class: "form-signin" do %>
<%= text_field_tag :email, params[:email], class: "form-control", autofocus: "", required: "", placeholder: "Email address" %>
<%= password_field_tag :password, nil, class: "form-control", required: "", placeholder: "Password" %></br>
<p class="button"><%= submit_tag "Log in", class: "btn btn-lg btn-primary btn-block" %></p>
<% end %>
<%= link_to "Register", "/sign_up" %>
<% if defined?(#error) %>
<div class="error">
<%= "*" + #error %>
</div>
<% end %>
<% if defined?(#notice) %>
<div class="error">
<%= "*" + #notice %>
</div>
<% end %>
</td>
<td class="welcome-msg white">
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<h1 class="form-signin-heading" >Welcome to your personal Twitter Manager!</h1>
<p>Use this site to keep track of your followers, see how many posts they've made and many more features!</p>
<p>It's a really cool site, check it out! It's free!</p><br/><br/>
</td>
</tr>
</table>
</div>
<% end %>
<% end %>
Dashboard Controller:
class DashboardController < ApplicationController
helper_method :logged_in?
def new
end
def logged_in?
if defined? session[:user_id]
true
else
false
end
end
end
Sessions Controller:
class SessionsController < ApplicationController
helper_method :logged_in?
# Use this to detect device type:
# request.env['mobvious.device_type']
def new
end
def create
user = User.authenticate(params[:email], params[:password])
if user
session[:user_id] = user.id
#notice = "Logged in!"
redirect_to "/dashboard"
else
#error = "Invalid email or password"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Logged out!"
end
def logged_in?
if defined? session[:user_id]
redirect_to "/dashboard"
else
redirect_to "/"
end
end
end
Routes:
TwitterApp::Application.routes.draw do
get "dashboard/new"
get "users/new"
get "sessions/new"
get "log_out" => "sessions#destroy", :as => "log_out"
get "" => "sessions#new", :as => "log_in"
get "sign_up" => "users#new", :as => "sign_up"
get "dashboard" => "dashboard#new", :as => "dashboard"
root :to => "sessions#new"
resources :users
resources :sessions
end
Don't use defined? to check for the presence of hash values. It will always return a non false value:
some_hash = { :some_key => nil }
defined? some_hash[:some_key] # => "method"
defined? some_hash[:i_dont_exist] # => "method"
See the docs on this for more info.
In rails you can use session[:user_id].present?. This will check that the value at that key is not blank or nil. Also a better way to delete from the session is to call delete on it: session.delete(:user_id) or session.clear if you want to wipe everything.

RailsTutorial.org book design question

Hi I worked through Michael Hartl's RAILSTUTORIAL book and I have a question about how he builds the user's show page.
The page is supposed to list all the posts a user has made.
UsersController
def show
#user = User.find(params[:id])
#posts = #user.posts.paginate(:per_page => "10",:page => params[:page])
#title = #user.name
end
users/show.html.erb
<table class="profile" summary="Profile information">
<tr>
<td class="main">
<h1><%= #user.name %></h1>
<%= render 'follow_form' if user_signed_in? %>
<% unless #user.posts.empty? %>
<table class="posts" summary="User posts">
<%= render #posts %> # this goes to posts/_post and sends the object as post
# that makes the _post view use a local variable correct?
</table> # is there a way to do with with an #post variable?
<%= will_paginate #posts %>
<% end %>
</td>
<td class="sidebar round">
<%= link_to avatar_for(#user), #user.avatar.url %><br />
<strong>Name</strong> <%= #user.name %><br />
<strong>URL</strong> <%= link_to user_path(#user), user_path(#user) %>
<strong>Posts</strong> <%= #user.posts.count %>
<%= render 'shared/stats' %>
</td>
</tr>
</table>
posts/_post.html.erb
<tr>
<td class="post">
<span class="title"><strong><%= link_to post.title, post %></strong></span><br />
<span class="timestamp">
Posted <%= time_ago_in_words(post.created_at) %> ago. </span>
Likers<span id="likers"><br />
</span>
</td>
<% if current_user?(post.user)%>
<td>
<%= link_to "delete", post, :method => :delete,
:confirm => "You sure?",
:title => post.content %>
</td>
<%end%>
</tr>
I need to render a partial in the users view that uses the post object, but it asks for it as #post and since no #post has been defined in the show action of the user's controller I get a nil error.
It seem odd to me to go from the user's controller to the posts view and use a local variable, which if I understand local variables correctly can't be used outsider that view. Is there a way to assign the value of post in that view to #post in the users view?
Thanks for the help
You need to use a local variable in the partial, and assign it in the locals hash. This line is a shortcut for iterating through the array and rendering the partial. I'm not sure if this works anymore in Rails 3:
<%= render #posts %>
The way I would do it:
<% #posts.each do |post| %>
<%= render 'posts/post', :post => post %>
<% end %>
The slightly older way of rendering partials:
<% #posts.each do |post| %>
<%= render :partial => 'posts/post', :locals => {:post => post} %>
<% end %>

Resources