Rails4 -undefined method `name' for nil:NilClass 4 - ruby-on-rails

I am getting an error message that says undefined method 'name' in my show.html.erb page. Where it says #book.category.name it keeps saying undefined method name.
show.html.erb
<h1><%= #book.title %></h1>
<h3><%= #book.author %></h3>
<h4>Category: <%= #book.category.name %></h4>
<p><%= #book.description %></p>
<%= link_to "Back", root_path %>
<% if user_signed_in? %>
<% if #book.user_id == current_user.id %>
<%= link_to "edit", edit_book_path(#book) %>
<%= link_to "Delete", book_path(#book), method: :delete, data: {confirm: "Are you sure you want to delete book?"} %>
<% end %>
<% end %>
Books_Controller.rb
class BooksController < ApplicationController
before_action :find_book, only: [:show, :edit, :destroy, :update]
def index
if params[:category].blank?
#books = Book.all.order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#books = Book.where(:category_id => #category_id).order("created_at DESC")
end
end
def show
end
def new
#book = current_user.books.build
#categories = Category.all.map{ |c| [c.name, c.id]}
end
def create
#book = current_user.books.build(book_params)
#book.category_id = params[:category_id]
if #book.save
redirect_to root_path
else
render 'new'
end
end
def edit
#categories = Category.all.map{ |c| [c.name, c.id]}
end
def update
#book.category_id = params[:category_id]
if #book.update(book_params)
redirect_to book_path(#book)
else
render ' new'
end
end
def destroy
#book.destroy
redirect_to root_path
end
private
def book_params
params.require(:book).permit(:title, :description, :author, :category_id, :book_img)
end
def find_book
#book = Book.find(params[:id])
end
end
Book.rb
class Book < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_attached_file :book_img, :styles => { :book_index => "250x350>", :book_show => "325x475>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :book_img, :content_type => /\Aimage\/.*\Z/
end
Category.rb
class Category < ActiveRecord::Base
has_many :books
end

Just make sure that specific book has category or just cover it into if statement like below:
<% if #book.category %>
<h4>Category: <%= #book.category.name %></h4>
<% end %>

In case you have to leave category empty is use #try:
<h4>Category: <%= #book.category.try(:name) %></h4>

You need to make sure that the instance #book has a category object.
<h4>Category: <%= #book.category ? #book.category.name : "This book has no category" %></h4>

Related

Keep getting ActionController::UnknownFormat for nested resource view

Every time I go to this link /books/2/chapter I get this error:
ChaptersController#index is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: []
Please show me where I am going wrong and any other improvements I can make to my code.
These are my controllers
class ChaptersController < ApplicationController
def show
#chapter =Chapter.find(params[:id])
#sections = Section.all
end
def index
#chapters = Chapter.all
#book = Book.find(params[:book_id])
end
def new
#chapter = Chapter.new
#book = Book.find(params[:book_id])
end
def edit
#chapter = Chapter.find(params[:id])
end
def create
#chapter = Chapter.new(chapter_params)
#book = Book.find(params[:book_id])
if #chapter.save
redirect_to #chapter
else
render 'new'
end
end
def update
#chapter = Chapter.find(params[:id])
if #chapter.update(chapter_params)
redirect_to #chapter
else
render 'edit'
end
end
def destroy
#chapter = Chapter.find(params[:id])
#chapter.destroy
redirect_to chapters_path
end
private
def chapter_params
params.require(:chapter).permit(:title,:text)
end
end
and
class BooksController < ApplicationController
def show
#book = Book.find(params[:id])
#chapters = Chapter.all
end
def index
#books = Book.all
end
def new
#book = Book.new
end
def edit
#book = Book.find(params[:id])
end
def create
#book = Book.new(book_params)
if #book.save
redirect_to #book
else
render 'new'
end
end
def update
#book = Book.find(params[:id])
if #book.update(book_params)
redirect_to #book
else
render 'edit'
end
end
def destroy
#book = Book.find(params[:id])
#book.destroy
redirect_to books_path
end
private
def book_params
params.require(:book).permit(:title,:text,:bookcover,:authorpic,:author)
end
end
These are my models
class Chapter < ApplicationRecord
has_many :sections, dependent: :destroy
belongs_to :book
validates :title, presence: true,
length:{minimum: 5}
end
and
class Book < ApplicationRecord
has_many :chapters, dependent: :destroy
has_attached_file :bookcover, styles: { medium: "300x300>", thumb: "100x100>" }
has_attached_file :authorpic, styles: { medium: "300x300>", thumb: "100x100>" }
validates_attachment_content_type :bookcover, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
validates_attachment_content_type :authorpic, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
validates :title, presence: true,
length:{minimum: 5}
end
These are my routes
Rails.application.routes.draw do
devise_for :users
root to: 'pages#home'
get 'about', to: 'pages#about'
resources :contacts, only: :create
get 'contact-us', to: 'contacts#new', as: 'new_contact'
get 'bookclub', to: 'pages#bookclub'
get 'podcast', to: 'pages#podcast'
resources :essays do
resources :comments
end
resources :podcasts do
resources :podcomments
end
resources :books do
resources :chapters do
resources :sections do
resources :bookcomments
end
end
end
end
This is my chapters/_index.html.erb file
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col"><h3>Chapters</h3>
</div>
</div>
<%= link_to 'New chapter', new_book_chapter_path(#book) %>
<% #chapters.each do |chapter| %>
<ul class="demo-list-item mdl-list">
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<%=link_to chapter.title, book_chapter_path(#book, chapter)%>
</span>
</li>
</ul>
<%= link_to 'Edit', edit_book_chapter_path(#book, chapter) %>
<%= link_to 'Destroy', book_chapter_path(#book, chapter),
method: :delete,
data: { confirm: 'Are you sure?' } %>
<%end%>
This is my books/show.html.erb file
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col"><h3><%= #book.title %></h3>
</div>
<%= render 'chapters/index', chapters: #chapters %>
<p>
<%= link_to 'Edit', edit_book_path(#book) %> |
<%= link_to 'Back', books_path %>
</p>
Why chapters/_index and not chapters/index? This must be the error.
I think you have some errors in your controllers.
def index
# Do you really want all chapters? (from all books)
# #chapters = Chapter.all
#book = Book.find(params[:book_id])
# I think you want only this book's chapters
#chapters = #book.chapters
end
def show
#chapter =Chapter.find(params[:id])
# The same thing. You want only sections from this chapter
# #sections = Section.all
#sections = #chapter.sections
end
EDIT
I see you are using chapters/_index as a partial from book/show. But you are also using the same in ChaptersController#index. Although not very nice you could do this:
chapters/index.html.erb
<%= render partial: 'chapters/_index', locals: { book: #book, chapters: #chapters } %>
in chapters/_index, replace #chapters by chapters (without #) and #book by book (without #)

Rails - When assigning attributes, you must pass a hash as an argument 2

In my Rails 5 app, I have this error:
when I use this table to list the tags of a related object (in this case an Annotation)
<tbody>
<% object.tags.each do |tag| %>
<% unless tag.content.blank? %>
<tr>
<td style="word-wrap: break-word;" class="displaytagedit"><%= link_to tag.content, **[object, tag]**, method: :patch %></td>
It tries to open this link
http://localhost:3000/annotations/6/tags/24 (which appears correct)
and throws this error:
When assigning attributes, you must pass a hash as an argument.
On this part of my controller (below)
tagable = detect_tagable
#tag = tagable.tags.update(params[:id])
#tags = Tag.all
render '_tag_update'
end
It should call this form:
<%= simple_form_for #tag, html: { class: 'form-vertical', multipart: true },
wrapper: :horizontal_form,
wrapper_mappings: {
check_boxes: :horizontal_radio_and_checkboxes,
radio_buttons: :horizontal_radio_and_checkboxes,
file: :horizontal_file_input,
boolean: :horizontal_boolean
} do |f| %>
<%= f.error_notification %>
<%= f.input :content, placeholder: 'Tagged content', label: false %>
<%= f.association :tagtype, prompt: 'Select tag type', label: false, :collection => Tagtype.active.order(:name).where(:documenttype => object.documenttype_id) %>
<%= f.input :location, :as => :hidden, :input_html => { :value => 'x=0, y=0' }, label: false %>
<%= f.button :submit %>
<% end -%>
Tags are a reusable model on (for now) 2 objects.
This is the routes.rb
Rails.application.routes.draw do
root 'dashboard#index'
devise_for :users
resources :users, :documenttypes, :tagtypes, :business_partners
resources :documents do
resources :comments, :tags
get "pdf", on: :member
end
resources :annotations do
resources :comments, :tags
get "pdf", on: :member
end
Update
this is the tag controller:
class TagsController < ApplicationController
def create
tagable = detect_tagable
tagable.tags.create(tag_params)
redirect_to tagable_path(tagable)
end
def update
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
#tags = Tag.all
render '_tag_update'
end
def destroy
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
#tag.destroy
redirect_to tagable_path(tagable)
end
private
def tagable_path(tagable)
case tagable
when Document
document_path(tagable)
when Annotation
annotate_path(tagable)
else
fail 'Unknown tagable'
end
end
def detect_tagable
if params[:annotation_id]
Annotation.find(params[:annotation_id])
elsif params[:document_id]
Document.find(params[:document_id])
else
fail 'Tagable not found'
end
end
def tag_params
params.require(:tag).permit(:content, :location, :tagtype_id, annotation_attributes: { annotation_ids:[] }, document_attributes: { document_ids:[] })
end
end
Where is my error/mistake?
Can you show us your controller? probably it's a typo in object which really would be #object as this comment says
Anyway, send your controller code to confirm this
EDIT:
In your TagsController file you must set the update method like this:
def update
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
#tags = Tag.all #Or whatever query you want if you want to select more specific Tags
render '_tag_update'
end

No route matches {:action=>"index", :controller=>"features", :grounddetail_id=>nil} missing required keys: [:grounddetail_id]

I wanna fetch feature index page without going through grounddetail id. When i try to create a link in homepage i always get this error:
No route matches {:action=>"index", :controller=>"features", :grounddetail_id=>nil} missing required keys: [:grounddetail_id]
<%= link_to "Account Setting", edit_admin_registration_path %> |
<%= link_to "Log Out", destroy_admin_session_path, method: :delete %> |
<%= link_to "Featured Ground", grounddetail_features_path(#grounddetail) %> # Feature Link Where I get error
grounddetail controller looks :
class GrounddetailsController < ApplicationController
before_action :find_ground, only: [:show, :edit, :destroy, :update]
def index
#grounddetails = Grounddetail.all.order('created_at DESC')
#grounddetail = Grounddetail.first # With this code it run but with grounddetail id.
end
def new
#grounddetail = Grounddetail.new
end
def edit
end
def show
end
def create
#grounddetail = Grounddetail.new(ground_params)
if #grounddetail.save
redirect_to #grounddetail
else
render 'new'
end
end
def update
if #grounddetail.update(ground_params)
redirect_to #grounddetail
else
render 'edit'
end
end
def destroy
#grounddetail.destroy
redirect_to root_path
end
private
def find_ground
#grounddetail = Grounddetail.find(params[:id])
end
def ground_params
params.require(:grounddetail).permit(:name, :working_hours, :end_time, :address, :contact_no, :email, :number_of_grounds, :description, :featured_ground)
end
end
feature controller looks like :
class FeaturesController < ApplicationController
before_action :set_ground
def index
#grounddetails = Grounddetail.where(featured_ground: true).order("created_at DESC")
#features = Feature.includes(:grounddetail).where(grounddetail_id: #grounddetail.id)
end
def new
#feature = Feature.new
end
def show
#feature = Feature.find(params[:id])
end
def edit
#feature = Feature.find(params[:id])
end
def create
#feature = Feature.create(feature_params)
#feature.grounddetail_id = #grounddetail.id
if #feature.save
redirect_to grounddetail_features_path(#grounddetail)
else
render 'new'
end
end
def update
#feature = Feature.find(params[:id])
if #feature.update(feature_params)
redirect_to grounddetail_features_path(#grounddetail)
else
render 'edit'
end
end
def destroy
#feature = Feature.find(params[:id])
#feature.destroy
redirect_to grounddetail_features_path(#grounddetail)
end
private
def set_ground
#grounddetail = Grounddetail.find(params[:grounddetail_id])
end
def feature_params
params.require(:feature).permit(:featuring_start_time, :featuring_end_at)
end
end
Models:
grounddetail model:
has_many :features
feature model:
belongs_to :grounddetail
index.html.erb #feature index page
<h2>Featured Ground</h2>
<% #grounddetails.each do |grounddetail| %>
Name: <%= link_to grounddetail.name, grounddetail %><br>
Address: <%= grounddetail.address %><br>
Opening Hours: From<%= grounddetail.working_hours.strftime("%l:%M %P") %> To <%= grounddetail.end_time.strftime("%l:%M %P") %><br>
Featured : <%= check_box "Grounddetail", "Featured Ground", {checked: grounddetail.featured_ground, disabled: true} %><br>
<% if (grounddetail.featured_ground = true) && (grounddetail_id = #grounddetail.id) %>
<% #features.each do |feature| %>
Featuring Start Time : <%= feature.featuring_start_time.strftime('%e %b %Y %l:%M %P') %><br>
<%# feature.start_date_cannot_be_in_the_past %>
Featuring End At : <%= feature.featuring_end_at.strftime('%e %b %Y %l:%M %P') %><br>
<% end %>
<% end %>
<%= link_to "Add Featuring Time", new_grounddetail_feature_path(#grounddetail) %><br><br>
<% end %>
routes.rb
resources :grounddetails do
resources :features
end
Sorry for the mess up..

How to Add Current_User to Nested Attribute?

name
metric
date_value
result_value
None of the above attributes are showing when I load the index page.
I know its because of this line: <% if averaged.user == current_user %>
More specifically it's because of the nested attributes of date_value and result_value (because if I take out those nested attributes the name & metric will show)
What do I need to add to the controller to allow the nested attributes to show on the index page, and in effect all the attributes?
Thanks in advance for your service!
<div id="values" class="panel panel-default">
<div class="panel-heading"><h4><b>AVERAGE</b></h4></div>
<!-- Table -->
<table>
<% #averaged_quantifieds.each do |averaged| %>
<% if averaged.user == current_user %>
<th class="value">
<%= link_to edit_quantified_path(averaged) do %>
<%= averaged.name %>
<% end %>
(<%= averaged.metric %>)
</th>
<tbody class="value">
<td><%= averaged.date_value.strftime("%m-%Y") %></td>
<td><%= averaged.result_value %></td>
</tbody>
<% end %>
<% end %>
</table>
</div>
controller
class QuantifiedsController < ApplicationController
before_action :set_quantified, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#averaged_quantifieds = current_user.quantifieds.averaged
#instance_quantifieds = current_user.quantifieds.instance
#averaged_quantifieds = Result.all.order("date_value")
#instance_quantifieds = Result.all.order("date_value")
end
def show
end
def new
#quantified = current_user.quantifieds.build
#quantified = Quantified.new
end
def edit
end
def create
#quantified = current_user.quantifieds.build(quantified_params)
if #quantified.save
redirect_to quantifieds_url, notice: 'Quantified was successfully created'
else
render action: 'new'
end
end
def update
if #quantified.update(quantified_params)
redirect_to quantifieds_url, notice: 'Goal was successfully updated'
else
render action: 'edit'
end
end
def destroy
#quantified.destroy
redirect_to quantifieds_url
end
private
def set_quantified
#quantified = Quantified.find(params[:id])
end
def correct_user
#quantified = current_user.quantifieds.find_by(id: params[:id])
redirect_to quantifieds_path, notice: "Not authorized to edit this goal" if #quantified.nil?
end
def quantified_params
params.require(:quantified).permit(:categories, :name, :metric, :result, :date, results_attributes: [:id, :result_value, :date_value, :_destroy])
end
end
quantified.rb
class Quantified < ActiveRecord::Base
belongs_to :user
scope :averaged, -> { where(categories: 'averaged') }
scope :instance, -> { where(categories: 'instance') }
has_many :results
accepts_nested_attributes_for :results, :reject_if => :all_blank, :allow_destroy => true
CATEGORIES = ['averaged', 'instance']
end
Please let me know if you need any more code or comments to help bring this question to a resolution.
This will hopefully guide you in the right direction
This is odd to me
def index
#averaged_quantifieds = current_user.quantifieds.averaged
#instance_quantifieds = current_user.quantifieds.instance
#averaged_quantifieds = Result.all.order("date_value")
#instance_quantifieds = Result.all.order("date_value")
end
You define both of these twice and essentially overwrite each other?
If your attributes aren't showing, it doesn't have anything to do with the nesting, it has to do with the logic. So in other words, this logic
if averaged.user == current_user
is not evaluating to true, so check what each object is actually holding. You can do this in a dirty way by just inspecting it in the view
e.g. put <%= averaged.user.inspect %> and <%= current_user.inspect %>
Once you know what objects it's holding, go backwards in your code to how you altered them to this state. I suspect it'll go back to the controller where you have some issues.

Albums in rails

I would like to create an image gallery in rails. I have produced a setup that allows you to create an album and upload photos to it. However, I am stumped on how I could allow the user to set one of the existing images as the album cover in the image's index view.
Anyone have some ideas? I found that if I used radio buttons, I couldn't figure hout how to determine which image was selected by ajax. I also don't know how I would force only one image being set as album cover.
Here is my setup:
Controller
class Admin::AlbumsController < ApplicationController
respond_to :html, :json
def index
#albums = Album.all
end
def new
#album = Album.new
end
def create
#album = Album.new(params[:album])
if #album.save
flash[:notice] = "Successfully created album!"
redirect_to [:admin, :albums]
else
render "new"
end
end
def edit
#album = Album.find(params[:id])
end
def show
#album = Album.find(params[:id])
end
def update
#album = Album.find(params[:id])
#album.update_attributes(params[:album])
if #album.update_attributes(params[:album])
respond_with #album
flash[:notice] = "Successfully updated Album"
else
render "edit"
end
end
def destroy
#album = Album.find(params[:id])
#album.destroy
#id = #album.id
FileUtils.remove_dir("#{Rails.root}/public/uploads/image/picture/#{#id}", :force => true)
respond_to do |format|
format.js { render :layout => false }
end
redirect_to admin_albums_path
end
def random_image
#image_files = %w( .jpg .gif .png )
#files ||= Dir.entries(
"#{RAILS_ROOT}/public/uploads").delete_if { |x|
!#image_files.index(x[-4,4])
}
file = #files[rand(#files.length)];
#files.delete file
return "/images/logos/#{file}"
end
def ajaxUpdate
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:albumcover])
if #image.update_attributes(params[:image])
flash[:notice] = "Successfully updated Image"
else
render "edit"
end
end
end
class Admin::ImagesController < ApplicationController
respond_to :html, :json
#before_filter :split_hash, :only => [ :create, :update ]
def index
#album = Album.find(params[:album_id])
#images = #album.images.all
end
def new
#album = Album.find(params[:album_id])
#image = #album.images.new
end
def create
params[:image][:source].each do |image|
#album = Album.find(params[:album_id])
#params = {}
#params['source'] = image
#image = #album.images.create(#params)
end
if #image.save
if params[:image][:source].size > 1
flash[:notice] = "Successfully added images!"
else
flash[:notice] = "Successfully added image!"
end
redirect_to [:admin, #album, :images]
else
render "new"
flash[:notice] = "Did not successfully add image :("
end
end
def show
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:id])
end
def edit
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:id])
end
def update
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:id])
if #image.update_attributes(params[:image])
redirect_to [:admin, #album, :images]
flash[:notice] = "Successfully updated Image"
else
render "edit"
end
end
def destroy
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:id])
#image.destroy
#albumid = #album.id
#id = #image.id
FileUtils.remove_dir("#{Rails.root}/public/uploads/image/picture/#{#albumid}/#{#id}", :force => true)
redirect_to admin_album_images_path(#album)
end
def ajaxUpdate
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:albumcover])
if #image.update_attributes(params[:image])
flash[:notice] = "Successfully updated Image"
else
render "edit"
end
end
# def split_hash
# #album = Album.find(params[:album_id])
# #image = #album.images
# array_of_pictures = params[:image][:picture]
# array_of_pictures.each do |pic|
# size = array_of_pictures.size.to_i
# size.times {#image.build(params[:image], :picture => pic)}
# #image.save
# end
# end
end
Models
class Album < ActiveRecord::Base
attr_accessible :title, :description, :album_id
has_many :images, :dependent => :destroy
validates :title, :description, :presence => true
end
class Image < ActiveRecord::Base
attr_accessible :title, :description, :source, :album_id, :albumcover, :image, :image_id
belongs_to :album
accepts_nested_attributes_for :album
mount_uploader :source, PictureUploader
end
View
<% content_for :head do %>
<%= stylesheet_link_tag 'admin/images' %>
<%= javascript_include_tag "admin.js" %>
<% end %>
<% content_for :menu do %>
<li class="menu_item"><%=link_to "New Album", :controller => "albums", :action => "new" %></li>
<li class="menu_item"><%= link_to "Add Images", {:controller => "images", :action => "new"}, :class => "highlight_menu"%> </li>
<% end %>
<%= link_to "< Back", admin_albums_path, :id => "return_link" %> </br>
<h1 class="section-title"> <strong style="font-weight: 600;"><%=best_in_place [:admin,#album], :title, :ok_button => :confirm %></strong></h1>
<h4 class="album-desc"><%= best_in_place [:admin,#album], :description, :type => :textarea, :ok_button => :confirm%></h4>
<%= form_tag admin_album_images_path(#album) do %>
<% if !#images.blank? %>
<% #images.each do |image| %>
<div class="item">
<div class="image-box">
<div class="source">
<%= image_tag image.source %>
</div>
</div>
<div class="info">
<div class="item-links">
<%= link_to "Edit", edit_admin_album_image_path(#album, image.id), :id => "edit"%>
<%= link_to "Delete",
admin_album_image_path(#album, image.id),
:class => "item-link delete-image",
:method => :delete,
:remote => true,
:confirm => "Are you sure?" %>
</div>
</div>
</div>
<% end %>
<% else %>
<p class="alert">No images in this album</p>
<% end %>
<% end %>
Answer!
*albums_controller*
def albumCoverSet
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:albumcover])
if #image.update_attributes(params[:image])
flash[:notice] = "Successfully updated Image"
else
render "edit"
end
end
* album view *
<div class="image">
<%= image_tag album.images.find(album.albumcover_id).source, :class => "image" %>
</div>
model
class Album < ActiveRecord::Base
attr_accessible :title, :description, :album_id, :albumcover_id
has_many :images, :dependent => :destroy
has_one :albumcover, :class_name => "Image"
validates :title, :description, :presence => true
end
You can add a 'primary_image_id' to the Album in a migration.
has_one :primary_image, :class_name => 'Image'
In your form, you can show all album.images and select one. Radio buttons should work just fine.
Submitting the value of the param would set the primary_image_id.

Resources