When working with one-to-many relations in with Rails 3.1 and Mongoid, I keep bumping my head on undefined method `name' for nil:NilClass even when I'm positive it exists. Either it's a stupid mistake or then there's something wrong with Mongoid. Let's elaborate:
I keep getting this error:
NoMethodError in Leads#index
Showing /app/views/leads/index.html.haml where line #19 raised:
undefined method `heat' for nil:NilClass
Extracted source (around line #19):
16: - #leads.each do |lead|
17:
18: %tr
19: %td #{lead.visit.heat}°
20: %td
21: = link_to lead.name, :controller => "leads", :action => "show", :id => lead.id
And when I try to reproduce this in the console, it seems to work great. Truly mind-boggling..
Here's the code from relevant places:
-------------------------*SCHNIP*------------------------------------
class Company
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
has_one :visit
def self.get_companies
visits = Visit.get_visits
companies = self.all
visits.each do |visit|
unless companies.name.include?(visit.name)
new_company = self.new
new_company.name = visit.name
new_company.visit = visit
new_company.save
end
end
#return companies for current instance
return Company.where(:visit.exists => true)
end
end
-------------------------*SCHNIP*------------------------------------
class Visit
include Mongoid::Document
include Mongoid::Timestamps
field :heat, type: Integer
field :name, type: String
belongs_to :company
def self.get_visits
return self.all
end
end
-------------------------*SCHNIP*------------------------------------
class LeadsController < ApplicationController
def index
#selected = 'visitors'
#leads = Company.get_companies
end
end
-------------------------*SCHNIP*------------------------------------
app/views/leads/index.html.haml
- #leads.each do |lead|
%tr
%td #{lead.visit.heat}°
%td
= link_to lead.name, :controller => "leads", :action => "show", :id => lead.id
-------------------------*SCHNIP*------------------------------------
I just ran into this, I had an Account -> Transaction relationship.
I embedded Transactions into Account, which then prevented me from making Transactions on their own. I got the same error message.
But if I did this:
a = Account.create
a.transactions.create
Then everything went fine. Hope that helps explain something.
Not the answer to your question but why do you have:
def self.get_visits
return self.all
end
In your Visit model is this not the same as calling Visit.all ?
When you call lead.name lead is nilclass it not a company as i guess you are expecting it to be.
It all seems a bit odd and far to much code for what you are trying to achieve.
I would go back to basics.
The error message you presented actually suggests that the lead in question has a Null lead.visit somewhere. You have a defined "lead", but its "visit" was not defined.
Are you sure that you can use .exists as in :visit.exists? It seems that you are receiving some leads which actually do not have that visit field.
To check, you could try something like
- #leads.each do |lead|
- if lead.visit
%tr
%td #{lead.visit.heat}°
%td
= link_to lead.name, :controller => "leads", :action => "show", :id => lead.id
Please check if this works.
Related
I have followed tutorial from Simply Rails 2, but I got NoMethodError
this is my story.rb model :
class Story < ApplicationRecord
validates :name, :link, presence: true
has_many :votes do
def latest
find :all, :order => 'id DECS', :limit => 3
end
end
end
this is my show.html.haml view :
%h2
%span#vote_score
Score: #{#story.votes.size}
= #story.name
#vote_form
= form_for #story, method: "post", :url => story_votes_path(#story) do
= submit_tag 'shove it'
%ul#vote_history
- if #story.votes.empty?
%em No shoves yet!
- else
= render :partial => 'votes/vote', :collection => #story.votes.latest
%p
= link_to #story.link, #story.link
Full Error desciption :
undefined method `latest' for #<Vote::ActiveRecord_Associations_CollectionProxy:0x00007f4234aea9c0>
Did you mean? last
Extracted source (around line #15):
%em No shoves yet!
- else
= render :partial => 'votes/vote', :collection => #story.votes.latest ##this is line 15
%p
= link_to #story.link, #story.link
Rails.root: /home/kevin/shovell2
Can anyone help me to solve this ? Thank You.
Are you sure you want to pass that block to has_many? I think what you want is declaring that latest method in the Vote model, maybe a scope
scope :latest, -> { order('id DESC').limit(3) }
or the same with a method
def self.latest
order('id DESC').limit(3)
end
A note about the version of rails you're using: you are making your model subclassing ApplicationRecord, and that exists in the latest versions of rails (probably from rails 5 upward). On the other hand this method seems from a very old version of rails, probably 2 find :all, :order => 'id DECS', :limit => 3
You need to add latest to your Vote model not to your Story model. And it can be like this instead of method.
class Vote < ApplicationRecord
...
scope :latest, -> { order('id DESC').limit(3) }
...
end
I'm trying to archive a Product by using a link_to in Rails 5.
In the view:
<% #products.each do |product| %>
<%= link_to product_path(product, "product[archived]" => true),
:method => :put,
data: { confirm: 'Sure?' } do %>
<i class="fa fa-archive color-danger" aria-hidden="true"></i>
<% end %>
<% end %>
But after clicking on the link my ProductsController throws the following error:
undefined method `to_sym' for {:archived=>false}:Hash Did you mean? to_s to_yaml to_set
The error points to the if #product.update(product_params) line. Full update method is:
def update
#product = Product.find(params[:id])
puts #product.id
if #product.update(product_params)
redirect_to #product
else
render 'edit'
end
end
EDIT
Actually the offending line was a badly written validation in my Product model.
I had: validates_uniqueness_of :code, :scope => [:archived => false], where it should have been validates_uniqueness_of :code, conditions: -> { where.not(archived: true) }.
In hindsight it was a silly mistake, but now I'm wondering why it was throwing such a strange error and worse, the error was in the controller...
The scope attribute on the validation is expecting either a single attribute or an array of attributes from your model, something like
class Product < ApplicationRecord
validates_uniqueness_of :code, :scope => :archived
end
As it turns out, including the :scope option adds a where clause during the validation which looks like where(:archived => false) based on my example above.
From your original code validates_uniquesness_of :code, :scope => { :archived => false }, this results in the scope executing where({:archived => false} => nil). You can see that the hash argument to where is definitely off.
Later in the stack, ActiveRecord is going to try to turn the key from the argument hash into a symbol with to_sym and look for that key as an attribute on the Product model. However, the key in this case is the hash {:archived=>false} which does not respond to to_sym, and here the undefined method error gets raised.
The reason the error "appeared" in the controller is because the line product.update(product_params) in your controller is the beginning of the call chain that led to the bad validation being called in the model, which you have determined was the source of the error.
I'm using nested attributes in my Ruby on Rails app (4.0.2) such that survey has_many questions and accepts_nested_attributes_for questions and question belongs_to survey.
The problem that I have run into is that when I only want to look at the questions that belong to a particular survey I get an "undefined method "id" for nil:NilClass"-error. When on the other hand I look at all the questions the index action works without problems.
My questions controller index action:
def index
#questions = Question.where(:survey_id => #survey.id).all # if instead I use #questions = Question.all it works fine, but is not what I want.
##questions = #survey.questions.all
#surveys = Survey.all
#survey = Survey.first
end
My surveys/index.html.erb page:
<%= link_to("questions", { :controller => 'questions', :survey_id => survey.id }, :class => 'btn btn-xs') do %>
<%= glyph 'th-list' %>
<%- end -%>
My Question model:
class Question < ActiveRecord::Base
belongs_to :survey
scope :sorted, lambda { order("questions.created_at ASC")}
end
I also use a before_action that I call find_survey which looks like this:
def find_survey
# If in each action calling this method (find_survey) has :survey_id sent
if params[:survey_id]
# We will then go to the database and look for (and find) :survey_id and set that to #survey.
#survey = Survey.find(params[:survey_id])
end
end
Could anybody point me in the right direction?
The undefined method on NilClass is because your instance variable #survey is nil, and when you're calling Question.where(:survey_id => #survey.id).all you're getting that error.
If you're associations are set up right you should be able to run #survey.questions and not have to perform the search on Questions. That's part of ActiveRecord rails magic. You SHOULDN'T have to call #survey.questions.all because that will return all intances of the Question class, leave that off and you should be good to go.
As far as why this isn't working for you now, it may just be an order thing — you're calling #survey before you define it on the line below.
Based on the error you posted, #survey is likely nil in this line:
#questions = Question.where(:survey_id => #survey.id).all
So maybe your "before_action" is not being called?
I'm studing Ruby on Rails with the "RoR Bible" by Thimothy Fisher. But one of the examples doesn't work. It's code - http://pastebin.com/gtjLsdt0
The error is: NoMethodError in Contact#new where line #4 raised:
undefined method `merge' for "first_name":String
that's my contact_controller. I'm just retyping example's code, and there weren't any words about merge
class ContactController < ApplicationController
def index
#contacts = Contact.find(:all);
end
def show
end
def new
#contact = Contact.new;
end
def create
end
def update
end
end
What is wrong??
Lol that example is completely wrong!
Instead of writing sth like this:
<%= f.text_field 'contact', 'first_name' %>
You should write
<%= f.text_field :first_name %>
Because by using f.field_type you assign the field to the :contact form which provides the f methods by iteration! Also you can write
<%= f.label :first_name, "description of first_name" %>
Instead of writing it manual!
// I loked up the book you refered it seems to be quit outdated. You may buy "The Rails 3 Way" or sth. that can hold up to the current rails version!
In my application I have a very simple association. A User has_many Emails, this association works as expected with create/update/delete.
How ever when I attempt to display the information this is where things become some what difficult.
In my controller I have the following bit of code:
def prospective_user
#users = Account::User.all_by_user_status(0)
#users.each do |u|
u.email = u.email.get_primary_email
end
end
What this should do is create an instance of the Account::Email model with a single record.
The method get_primary_email looks like this:
def self.get_primary_email
first :conditions => ["is_primary = 1"]
end
The issue I am seeing is with in my view, I am getting the exception below. This is a bit confusing as I am not looping over the email object.
undefined method each' for #<Account::Email:0x7fcc3a5c49d8>
The code I am using to test with is this:
<% #users.each do |u|%>
<p>
<%=debug(u.email)%>
</p>
<% end %>
Do something like that instead:
class User < ActiveRecord::Base
has_many :emails
has_one :primary_email, :class_name => 'Email',
:conditions => { is_primary: 1 }
end
Then you can call user.primary_email directly
# your controller
def prospective_user
#users = Account::User.includes(:primary_email).where(:status => 0)
end
# your view
<% for user in #users %>
<%= user.primary_email %>
<% end %>