I have an app where each Site belongs to a Trust and a Trust has many Sites.
I'm building the JSON result with Jbuilder like this:
json.array! (#sites) do |site|
json.id site.id
json.name site.name
json.city site.city
json.state site.state
json.country site.country
json.start_date site.start_date
json.end_date site.end_date
json.trust site.trust, :id, :name # throws error here
end
The final line of the block returns an error of NoMethod, "a undefined method `id' for nil:NilClass."
However, the Site model belongs_to :trust and the Trust model has_many :sites.
When I run the Rails console, I can access site.trust.id and site.trust.name as I would expect.
Any ideas what's wrong?
I got it to work. I basically dumped my database and then ran the migrations again. It now works fine.
Any ideas why this would be? It worked fine previously, but then it threw the error. I just want to make sure I don't make the same mistake again.
Related
I've been stuck on trying to write a system test for a form that manually works in the browser.
I have a Speaker model that has_one :individual. The form field looks like this:
<fieldset>
<%= form.label :speaker, "Who said it?" %>
<%= form.collection_select :speaker_id, Speaker.all.sort_by(&:full_name), :id, :full_name %>
</fieldset>
The custom full_name method in the Speaker model looks like this:
def full_name
if individual
"#{individual.first_name} #{individual.last_name}"
end
end
The if individual conditional is a smell, but without it, I get this error:
Minitest::UnexpectedError: ActionView::Template::Error: undefined method `first_name' for nil:NilClass
If I add the if individual conditional then the error looks like this:
Minitest::UnexpectedError: ActionView::Template::Error: comparison of String with nil failed
I'm confused because I'm using a similar pattern to sort collection selects by a full_name in other models, but this is the only one that raises an error in the system test. Also everything works as expected when I manually test in the browser.
I can also access the the first_name last_name and full_name methods in the Individual model in the console, no problem.
This also doesn't cause an error (and I can use :full_name to display the name in the browser, but it's just not alphabetical:
<%= form.collection_select :speaker_id, Speaker.all, :id, :full_name %>
How can I fix this error in Capybara? Or is there a better way to return Speaker.all in the collection_select sorted alphabetically?
Update:
I simplified this by not passing the Quote / Individual relationship through a Speaker model. Now, my Quote model belongs_to :individual and Individual has_many :quotes. This is also working in the browser, but I'm getting the same error with my system test:
<ActionView::Template::Error: undefined method `full_name' for nil:NilClass>
Here's one of the tests that is failing with this error...
require "application_system_test_case"
class QuotesTest < ApplicationSystemTestCase
setup do
#contributor = users(:contributor)
#contributor_quote = quotes(:contributor_quote)
#category = categories(:rock_and_roll)
#field = fields(:music)
#topic_one = topics(:recording)
#topic_two = topics(:songwriting)
#individual = individuals(:john_lennon)
#group = groups(:the_beatles)
end
test "visiting the index should be accessible to all" do
visit quotes_path
assert_text #contributor_quote.body
click_on #contributor_quote.body
assert_current_path quote_path(#contributor_quote)
end
end
My Individual model has this method in it:
def full_name
"#{first_name} #{last_name}"
end
And this is the part of the view that is causing the failure:
Speaker: <%= #quote.individual.full_name %>
If I include save_and_open_page the error looks like this...
I tried adding .strip as Thomas' answer suggested, but that's not helping.
Again, the only problem is this system test. It works fine in the browser.
Without actually seeing any of the test code the error is coming from it's impossible to know for sure, and I have no idea where Capybara is fitting into this. I'm guessing that what you have is a Speaker model that seems to depend on there being an individual associated with it, but that's not actually enforced anywhere so when you create the speaker instance in your test without an associated individual it's not being flagged as invalid. If Speaker is supposed to support there not being an associated individual then your issue is that your full_name method is returning nil when a string is required. To fix that you could do
def full_name
"#{individual&.first_name} #{individual&.last_name}".strip
end
to give you the full name when individual does exist, and an empty string when it doesn't
in my listing model i setup a method
def set_listing_number
listing_number="TM#{created_at.year}#{id}"
end
i have a couple of records that was created before i ran the migration to create the listing_number column. i wanted to update all the records at once but keep receiving this error.
here's the code that i ran that produce the error in console verifying if the method . it works i cannot save the assignment.
listing_number=listing.set_listing_number
=> "TM2014574"
2.0.0-p247 :003 > listing_number.save
NoMethodError: undefined method `save' for "TM2014574":String
i tried a couple with no success , that i also found here like this one
Listing.all.each{|n| n.update_attributes(:listing_number =>"TM#{n.created_at.year})}
the question how do i update the previous record at once. probably it's pretty basic but can't figure it out. thanks
# This method in Listing Model
def set_listing_number
listing_number="TM#{created_at.year}#{id}"
end
# In controller
Listing.all.each do |listing|
listing.set_listing_number
listing.save
end
or you can refactor this as
Listing.all.each do |listing|
listing.update listing_number: "TM#{listing.created_at.year}"
end
You're calling save on a string. You need listing.save in your code.
So, I'm a Rails newbie and may be missing something obvious, but I'm a bit flabbergasted as to why I'm getting a NoMethodError when I attempt to eager load an association using .includes.
Here's my code:
forecasts_controller.rb
def show
#forecast = Forecast.find(params[:id])
#forecast_projects = Project.includes(:project_type).where("forecast_id =?", params[:id])
end
_project.html.erb (this file is a collection partial rendered in the Forecast action)
<%= project.project_type.title %>
For some reason, this produces the following error:
NoMethodError in Forecasts#show
Showing /path where line #1 raised:
undefined method `title' for nil:NilClass
Oddly enough, if I change forecasts_controller.rb to...
def show
#forecast = Forecast.find(params[:id])
#forecast_projects = Project.joins(:project_type).where("forecast_id =?", params[:id])
end
Suddenly everything starts working perfectly. Can someone help me figure out what I'm missing here (and excuse my lack of experience)?
Your code does not work because there is one (or more) project having no project_type associated.
The big difference between joins and includes:
joins retrieve only the records that have at least 1 association
includes retrieve the records and load their association if it exists
Rails :include vs. :joins
That means when you call:
#forecast_projects = Project.includes(:project_type).where("forecast_id =?", params[:id])
# loads all the projects AND their associated project_type if exists
#forecast_projects = Project.joins(:project_type).where("forecast_id =?", params[:id])
# loads all the projects HAVING at least 1 project_type associated
To clearly see the difference, try this:
Project.includes(:project_type).count # total number of entries in projects table
Project.joins(:project_type).count # number of projects having at least 1 project_type
To fix your problem, you can try to display the title of the associated project_type if it exists:
<%= project.project_type.try(:title) %>
# will print the project_type.title if exists, prints nothing if project_type.nil?
<%= project.project_type.try(:title) || 'No ProjectType for this Project' %>
# will print the string if project_type is nil
You have at least one project without project_type. When you use includes rails selects all records and fails on the one without project_type. When you use joins it selects only those with project_type, but doesn't include them.
To fix the problem you better find the bad record and add the project_type to it and add validation to avoid this error in future. But if it's ok to have projects with blank project_type then use both joins and includes like Project.joins(:project_type).includes(:project_type).
I have a Model "Tag" that links to the dbpedia article for a particular topic. I want to create a virtual attribute that will use this dbpedia URI to generate a wikipedia URI. Here's roughly what the class looks like:
class Tag < ActiveRecord::Base
# Validation
validates_presence_of :dbpedia_uri, :label
#Virtual Attribute
def wikipedia_uri
"#{dbpedia_uri}".gsub("dbpedia.org/resource", "wikipedia.org/wiki")
end
end
When I go into my console and try to check Tag.all[1].wikipedia_uri, I get the following error:
NoMethodError: undefined method `wikipedia_uri' for #<Tag:0xa0c79ac>
Additionally, I have a second Model (Map) with virtual attributes that do work, but when I change them, I still get the old value. So when the code is:
def thumbnail_uri
"#{map_base_uri}/thumbnails/#{identifier}.jpg"
end
Map.all[1].thumbnail_uri returns something like: "http://WEBSITE/maps/thumbnails/g3201b.ct002662.jpg"
and when I change the code to:
def thumbnail_uri
"test"
end
I still get the output: "http://WEBSITE/maps/thumbnails/g3201b.ct002662.jpg"
I've tried reloading my Rails Console, but it still doesn't seem to be updating the virtual attributes. Any thoughts on what could be causing this issue?
Figured out the issue. I was stupidly running my console in a directory for a duplicate backup set of files, so all of the methods and variables from the backup were available in the console, but my changes to the current code weren't affecting it
I needed an error object to pass errors between controllers and js views for ajax responses. I wanted to use ActiveModel::Errors since then I could easily merge errors from model validation to non-model errors. But Ive been having some problems using this approach.
Using ActiveModel::Errors.new(nil)
If I try and call to_a() like so:
#errors = ActiveModel::Errors.new(nil)
#errors[:test] = "is a required field."
#errors.to_a().join("<br />")
I get the error:
undefined method `human_attribute_name' for NilClass:Class
Its trying to call the human_attribute_name for the nil I passed into Errors.new which is suppose to be a ActiveRecord Model.
I am wondering if anyone knows of a better way to handle errors or if the approach I am taken has already been made into some gem.
Chances are your validations are related to "something" that could be encapsulated in a model - it just doesn't need to be an ActiveRecord model.
You can use validations in any plain ruby object by doing something like this:
require 'active_model'
class Band
include ActiveModel::Validations
validates_presence_of :name
attr_accessor :name
end
Then, the usual suspects would work just fine:
b = Band.new
b.valid?
#false
b.name = "Machine Head"
b.valid?
#true