rails - if condition on view - undefined method `id' for nil:NilClass - ruby-on-rails

I have a class called #Subdomain:
Here is my controller:
class SubdomainsController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update]
before_action :set_subdomain, only: [:show, :edit, :update, :destroy]
before_action :redirect_to_subdomain, only: :show
before_action :redirect_to_subdomain_show, only: :root, unless: '#subdomain.nil?'
def root
render nothing: true
end
def index
#subdomains = Subdomain.all
end
def show
end
def new
#subdomain = Subdomain.new
end
def edit
end
def create
#subdomain = Subdomain.new(subdomain_params)
respond_to do |format|
if #subdomain.save
format.html { redirect_to #subdomain, notice: 'Subdomain was successfully created.' }
format.json { render :show, status: :created, location: #subdomain }
else
format.html { render :new }
format.json { render json: #subdomain.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #subdomain.update(subdomain_params)
format.html { redirect_to #subdomain, notice: 'Subdomain was successfully updated.' }
format.json { render :show, status: :ok, location: #subdomain }
else
format.html { render :edit }
format.json { render json: #subdomain.errors, status: :unprocessable_entity }
end
end
end
def destroy
#subdomain.destroy
respond_to do |format|
format.html { redirect_to subdomains_url, notice: 'Subdomain was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def redirect_to_subdomain_show
redirect_to subdomain_url(#subdomain) if #request_subdomain.eql? #subdomain.address
end
# Redirect to subdomain... if the current one isn't equal to #subdomain.address column
def redirect_to_subdomain
redirect_to subdomain_url(#subdomain, subdomain: #subdomain.address) unless #request_subdomain.eql? #subdomain.address
end
def set_subdomain
#subdomain = Subdomain.find(params[:id])
end
def subdomain_params
#subdomain.assign_attributes(tag_speciality: params[:subdomain][:tag_speciality].split(','))
params.require(:subdomain).permit(
:domain_id,
:address,
:title,
:description,
:is_published,
:button_text_client,
:button_text_service,
:cover,
:primary_colour,
:secundary_colour,
:contrast_colour,
:logo,
:find_clients,
:find_professional,
:start_relation,
:publications_wall,
:tag_speciality,
:cards_wall
)
end
end
On the view i created a condition:
<% if (!#subdomain.id.blank?) %>
<li>
<%= link_to cards_from_subdomain_path(subdomain_id: #subdomain.id) do %>
<i class="fa fa-search fa-lg"></i>
<span class="hidden-medium">
&nbsp <%= #subdomain.cards_wall %>
</span>
<% end %>
</li>
<li>
<%= link_to publications_from_subdomain_path(subdomain_id: #subdomain.id) do %>
<i class="icon-grid fa-lg"></i>
<span class="hidden-medium">
&nbsp <%= #subdomain.publications_wall %>
</span>
<% end %>
</li>
<% else %>
<li>Some thing</li>
<% end %>
Here is the model:
class Subdomain < ActiveRecord::Base
belongs_to :domain
has_many :cards
mount_uploader :cover, AssetsUploader
mount_uploader :logo, AssetsUploader
end
When the #subdomain exist is ok, everything works fine, but when it doesn't exist, i get this error message:
NoMethodError in Subdomains#index
undefined method `id' for nil:NilClass
<% if (!#subdomain.id.blank?) %>
What could i do to fix that? thanks

The quick and dirty solution would be to use #try (not recommended though)
<% if !#subdomain.try(:id).try(:blank?) %>
By the way, you can use #present? instead of negating a #blank? to make code more readable.
However, if I assume correctly and the #subdomain is an ActiveRecord model, you don't need to check if it's id is present. A following code should be sufficient in your case:
<% if #subdomain %>
(...)
<% else %>
(...)
<% end %>
If the #subdomain is not found, it will be a nil anyway - and then the if #subdomain condition will be evaluated as false - since nil is a falsy value.
And if you get this error because you happen to be rendering a collection like this:
= render 'subdomain', collection: #subdomains
...then you can just put that inside a condition...
<% if #subdomains.present? %>
= render 'subdomain', collection: #subdomains
<% else %>
<% # #subdomains are an empty collection %>
<% end %>

From your create action, id will definitely be created in your table. I don't still understand what you are trying to get to, for negating on #id.blank?.
Change the first line from your view. i.e.
<% if (!#subdomain.id.blank?) %>
to,
<% if #subdomains %>, which will definitely return all attributes on your Subdomain Table since its has being taken care of in your index action.
Another thing I do is wrap my if...else statement inside a loop, such the your view becomes:
<% #subdomains.each do |subd| %>
<% if subd.id.present? %> #you can use another attribute here instead of id. e.g. <% if subd.is_published == true %> since `is_published` is a boolean.
<li>
(#your codes here referenced with the format called `subd.whatever_attribute`)
</li>
<li>
(#your codes here referenced with the format called `subd.whatever_attribute`)
</li>
<% else %>
<li>Some thing</li>
<% end %>
<% end %>

Related

Not able to 'link_to' specific routes in code, but can access them by manually entering them into the browser

Am relatively new to Rails and have run into a problem I can't seem to solve.
I have setup a nested resource Model called Captable. It belongs_to a Company.
If I navigate to a certain view: for example http://localhost:3000/companies/9/captables/1 - everything works great. I see the right data.
I have 2 core problems I can't seem to solve, that I think have something to do with either naming conventions or routes.
Firstly, when I try access http://localhost:3000/companies/9/captables/new - I get the following error.
NoMethodError in Captables#new
Showing /Users/jamespember/calmcap/app/views/captables/_form.html.erb where line #2 raised:
undefined method `captables_path' for #<#<Class:0x00007f8a08edebc8>:0x00007f8a0984bfa8>
Extracted source (around line #2):
1
2
3
4
5
6
<%= form_with(model: #captable, local: true) do |form| %>
<% if #captable.errors.any? %>
<div id="error_explanation">
<h2>
Secondly - if I try link to link to the company_captables_pathfrom the /companies/ page by using the below, I get the following error.
View Cap Table: <%= link_to(#company.company_captables_path) %>
Error:
Showing /Users/jamespember/calmcap/app/views/companies/show.html.erb where line #30 raised:
undefined method `company_captables_path' for #<Company:0x00007f8a046a6630>
Here's some code snippets:
routes.rb
Rails.application.routes.draw do
devise_for :users
get 'dashboard/index'
root 'companies#index'
resources :companies do
resources :shareholders
resources :captables
end
end
captable.rb
class Captable < ApplicationRecord
belongs_to :company
end
captables_controller.rb
class CaptablesController < ApplicationController
before_action :set_captable, only: [:show, :edit, :update, :destroy]
def index
#captables = Captable.all
end
def show
#captable = Captable.find(params[:id])
end
def new
#captable = Captable.new
end
def edit
end
def create
#captable = Captable.new(captable_params)
respond_to do |format|
if #captable.save
format.html { redirect_to #captable, notice: 'Captable was successfully created.' }
format.json { render :show, status: :created, location: #captable }
else
format.html { render :new }
format.json { render json: #captable.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #captable.update(captable_params)
format.html { redirect_to #captable, notice: 'Captable was successfully updated.' }
format.json { render :show, status: :ok, location: #captable }
else
format.html { render :edit }
format.json { render json: #captable.errors, status: :unprocessable_entity }
end
end
end
def destroy
#captable.destroy
respond_to do |format|
format.html { redirect_to captables_url, notice: 'Captable was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_captable
#captable = Captable.find(params[:id])
end
def captable_params
params.require(:captable).permit(:version, :name, :company_id)
end
end
captables/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Version:</strong>
<%= #captable.version %>
</p>
<p>
<strong>Name:</strong>
<%= #captable.name %>
</p>
<p>
<strong>Company:</strong>
<%= #captable.company_id %>
</p>
captables/_form.html.erb - EDIT Updated
<%= form_with(model: [#company, #captable], local: true) do |form| %>
<% if #captable.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#captable.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% #captable.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.submit %>
</p>
<% end %>
schema.rb
Here's the schema for the table:
create_table "captables", force: :cascade do |t|
t.integer "version"
t.text "name"
t.integer "company_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Lastly, here's a screenshot of my rails routes.
Error when trying to access /companies/:id/captables/new
The rails route helper methods are added to the view context and controller - not models.
The link should read:
<%= link_to("Link text", company_captables_path(#company)) %>
Which is an implicit call to to:
<%= link_to("Link text", self.company_captables_path(#company)) %>
self being the view context.
When creating a form for a nested route you should pass an array:
<%= form_with(model: [#company, #captable], local: true) do |form| %>
# ...
<% end %>
You should also create the new instance from the assocation:
class CaptablesController < ApplicationController
before_action :set_company
before_action :set_captable, only: [:show, :edit, :update, :destroy]
# GET /companies/:company_id/captables/new
def new
#captable = #company.captables.new
end
# POST /companies/:company_id/captables
# POST /companies/:company_id/captables.json
def create
#captable = #company.captables.new(captable_params)
respond_to do |format|
if #captable.save
format.html { redirect_to #captable, notice: 'Captable was successfully created.' }
format.json { render :show, status: :created, location: #captable }
else
format.html { render :new }
format.json { render json: #captable.errors, status: :unprocessable_entity }
end
end
end
private
def set_company
#company = Company.find(params[:company_id])
end
# ...
end

How to add comments to statuses (like facebook)

I am trying to improve an exercice that I did on treehouse, the idea was to remake a little version of facebook thing, where users could publish statuses.
Now I want that a user can comment any statuses... And I am kinda lost...
The idea is to have all on the same page (if possible?, like on the real facebook)
So the comment form and the "displaying" content...
I hope anyone could help me :)
This is my github repository
I think I haven't understand how to call variables from a controller to another...
If someone could explain me with very easy words ... I am not native english speaker... so sometime it's difficult..
Here are the statuses part
controllers/statuses_controller/rb
class StatusesController < ApplicationController
before_filter :authenticate_user!, only: [:new, :create, :edit, :update]
before_action :set_status, only: [:show, :edit, :update, :destroy]
def index
#statuses = Status.all
#comments = Comment.all
end
def show
#status = Status.find(params[:id])
#comments = #status.comments.all
end
def new
#status = Status.new
#comment = #status.comments.build
end
def create
#status = Status.new(status_params)
#status.user = current_user
respond_to do |format|
if #status.save
format.html { redirect_to #status, notice: 'Status was successfully created.' }
format.json { render :show, status: :created, location: #status }
else
format.html { render :new }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #status.update(status_params)
format.html { redirect_to #status, notice: 'Status was successfully updated.' }
format.json { render :show, status: :ok, location: #status }
else
format.html { render :edit }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
def destroy
#status.destroy
respond_to do |format|
format.html { redirect_to statuses_url, notice: 'Status was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_status
#status = Status.find(params[:id])
end
def status_params
params.require(:status).permit(:user_id, :content, :comments_attribute[:id, :status_id, :content])
end
end
models/status.rb
class Status < ActiveRecord::Base
belongs_to :user
has_many :comments
default_scope -> { order(created_at: :DESC)}
validates :content, presence: true,
length: {minimum: 2}
validates :user_id, presence: true
end
views/comments/_form.html.erb I create a render in my index below:
<% simple_form_for #status.comments do |f|%>
<%= f.input :content %>
<%= f.button :submit %>
<% end %>
view/statuses/index.html.erb
<div class="page-header">
<h1>All of the Statuses</h1>
</div>
<%= link_to "Post A New Status", new_status_path, class: "btn btn-success"%>
<br>
<br>
<% #statuses.each do |status| %>
<div class="status">
<div class="row">
<div class="col-xs-1 avatar">
<%= image_tag status.user.avatar.thumb if status.user.avatar?%>
</div>
<div class="col-xs-7">
<h4><%= status.user.full_name%></h4>
</div>
</div>
<div class="row">
<div class="col-xs-8">
<p><%= simple_format(status.content) %></p>
</div>
</div>
<div class="row">
<div class="col-xs-8">
<%= link_to time_ago_in_words(status.created_at) + " ago", status %>
<% if status.user == current_user %>
<span class="admin">
| <%= link_to "Edit", edit_status_path(status) %> |
<%= link_to "Delete", status, method: :delete, data: {confirm: "Are you sure?"} %>
</span>
<% end %>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<p>Comments</p>
<% #comments.each do |comment| %>
<%= comment.content %>
<% end %>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<%= render "comments/form" %>
</div>
</div>
</div>
Now the comments part:
model/comment.rb
class Comment < ActiveRecord::Base
belongs_to :status
belongs_to :user
end
controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#comment = Comment.new(params_comment)
end
def index
#statuses = Status.all
#comments = Comment.all
#comment = Comment.find_by(params[:id])
end
private
def params_comment
params.require(:comment).permit(:content)
end
end
routes.rb
resources :statuses do
resources :comments
end
user.rb
that's a part of what I have in there
has_many :statuses
has_many :comments
your comments creation method should look like this:
#status = Status.find(params[:status_id])
#comment = #status.comments.create(comment_params)
#comment.user_id = current_user.id if current_user
#comment.save

Association between Post and Location

This my first ruby on rails application.
Model Location and Post, Location has many post.I create location as tree structure with ancestry gem.
class Post < ActiveRecord::Base
belongs_to :location, :counter_cache => true
end
class Location < ActiveRecord::Base
include Tree
has_ancestry :cache_depth => true
has_many :posts
end
This my Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
end
def new
#post = Post.new
end
def edit
end
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
private
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:name, :location_id)
end
end
Creating Post with location in Post _form.html.erb
<%= simple_form_for #post do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved: </h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.input :name %>
<%= f.select :location_id, Location.all.at_depth(4) { |l| [ l.name, l.id ] } %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My question are
First question- f.select :location_id , how display location name, not location id, i am using with simple form
Second question- Post index got error in <%= post.location.name %>
<% #posts.each do |post| %>
<tr>
<td><%= post.name %></td>
<td><%= post.location.name %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %> </td>
</tr>
<% end %>
First question:
Check the simple_form syntax for a dropdown. It is mentioned in the docs and you should be able to get this working by yourself.
Second question:
Does the offending post really have a related location? If it does not have one, it can not display the name of course. To counter these nil errors, use try:
<%= post.location.try(:name) %>
try will call the method name on location only if location is not nil.
For your first question :
Maybe you should read about "options_for_select"
http://guides.rubyonrails.org/form_helpers.html#option-tags-from-a-collection-of-arbitrary-objects
<% cities_array = City.all.map { |city| [city.name, city.id] } %>
<%= options_for_select(cities_array) %>
For your second question:
What is your error ?
Maybe one of your "post.location" is nil.
If so, try:
post.location.name unless post.location.nil?
Hope this can help

Post and Location Association with ancestry gem

My Rails application have two model. Location and Post, Location have many post.I am Using
ancestry gem.
class Post < ActiveRecord::Base
belongs_to :location, :counter_cache => true
end
class Location < ActiveRecord::Base
include Tree
has_ancestry :cache_depth => true
has_many :posts
end
My Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
end
def new
#post = Post.new
end
def edit
end
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:name)
end
end
If i am create new Post with which Location belongs in _form.html.erb
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved: </h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<%= select :location_id, Location.all.at_depth(4) { |l| [ l.name, l.id ] } %>
<div class="actions">
<%= f.submit %>
</div>
Browser show error message which is display bellow
ArgumentError in Posts#new
Not sure if this fixes your error, but:
To make the dropdown working, change the select line to:
<%= f.select :location_id, Location.all.at_depth(4) { |l| [ l.name, l.id ] } %>
This is because you want the formbuilder f to handle the creation of the form element.
You also have to whitelist the :location_id parameter in the controller:
def post_params
params.require(:post).permit(:name, :location_id)
end

Undefined variable or method when adding answers to questions

I'm trying to add answers to questions. Each questions has_one answer. I'm showing them on the comment page through partials except I keep getting this error:
undefined local variable or method `answer'
Here is part of my answers_controller.rb
class AnswersController < ApplicationController
before_action :set_answer, only: [:show, :edit, :update, :destroy]
def index
#question = Question.find params[:question_id]
#question.answers
end
def show
end
def new
#question = Question.find params[:question_id]
end
def edit
end
def create
#question = Question.find(params[:question_id])
#answer = #question.answers.create(answer_params)
respond_to do |format|
if #answer.save
format.html { redirect_to #comment, notice: 'Answer was successfully created.' }
format.json { render action: 'show', status: :created, location: #answer }
else
format.html { render action: 'new' }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
Here is my _question.html.erb partial where the answer partial is called:
<%=div_for(question) do %>
<div class="questioncontainer">
<p>
<%= question.body %>
<%= render :partial => #question.answers %>
<% if current_user == #comment.user %>
<div class="answercontainer">
<%= link_to 'Answer', new_question_answer_path(question)%>
</div>
</div>
</p>
<% end %>
<% end %>
Last, here is my _answer.html.erb partial:
<%=div_for(answer) do %>
<div class="questioncontainer">
<p>
<%= answer.body %>
</p>
</div>
<% end %>
Thanks for the help :)
Pass answer as local, via locals: {answer: #answer}
Use
<%= render question.answers %>
instead of
<%= render :partial => #question.answers %>
More info here: http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials

Resources