I'm having trouble parsing through a hash and then saving certain parts to my database. I'm able to iterate through it to get to the information that I need. My problem is updating the record in my database. I'm trying to update an existing record in my database based on if the country code for each country matches the country code in the XML parse.
In my controller I have:
class CountriesController < ApplicationController
def index
#countries = Country.all
travel_alerts = request_data('http://travel.state.gov/_res/rss/TAs.xml')
travel_warnings = request_data('http://travel.state.gov/_res/rss/TWs.xml')
# Sets warnings
warnings_array = travel_warnings["rss"]["channel"]["item"]
warnings_array.each do |warning|
#country = Country.find_by(code: warning["identifier"].strip)
#country.update(title: warning["title"],
description: warning["description"])
end
end
end
...
I've tried using .update and .save, but neither works. When I try update I get:
undefined method `update' for nil:NilClass
Does the update method need to be explicitly defined in the Country model? If so, what's the best way to have access to the parsed information since that's being done in the controller?
It raises an error, because Country by given code was not found, then find_by returns nil, on which update method does not exist.
Instead of find_by executrun find_by! - you should get ActiveRecord::RecordNotFound error
If it is expected some countries do not exist put your update statement within if block
if #country
#country.update ...
end
Related
I want to edit my record in the database with nested attributes. In my controller I have:
def edit
#chocolate = Chocolate.new.kinds.find_by_id(params[:chocolate_id])
end
and in my edit.html.erb I have:
form_for #chocolate do |choco|
but it gives me the next error:
undefined method model_name issue
I cannot understand why it gives me such error. Any options?
Those methods aren't really made to be mixed together in that way.
I'm guessing that you're trying to do something like this instead:
#chocolate = Chocolate.includes(:kinds).find(params[:chocolate_id])
Then you are querying the database for the Chocolate and associated Kind records instead of trying to instantiate a new record.
I have a system that lets users or guests write a review. If users write a review it is associated with their user_id. If guests write a review they are asked to provide a username which is stored in a column called "guest" in the reviews database.
I'm not entirely sure how to do this but what I've done with the professor_controller is:
def show
#review = Review.where(professor_id: #professor.id).order("created_at DESC")
#avg_review = #review.average(:hw)
if #review.user_id = !nil
#user = User.where(id: #review.user_id)
else
#user = #review.guest
end
render
end
However, this yields an error:
NoMethodError in ProfessorsController#show
undefined method `user_id=' for #<Review::ActiveRecord_Relation:0x007fed19228e28>
I was getting this error even before I put the if statement in. I had the same problem when my controller looked like:
def show
#review = Review.where(professor_id: #professor.id).order("created_at DESC")
#avg_review = #review.average(:hw)
#user = User.where(id: #review.user_id)
end
#review works fine so does #avg_review. The Reviews table has a user_id column and the Users table has an id column.
You are getting an ActiveRecord::Relation (a collection of Reviews), not a single instance of Review. You will need to do Review.where(professor_id: #professor.id).order("created_at DESC").first or Review.find_by_user_id(#professor.id) to return a single instance.
That said, it sounds like this relationship isn't modeled properly, or there's a better way to express what you want to do through other means. Can you route take in the id of a review as a param?
Your #review variable actually holds an ActiveRecord::Relation object, like it clearly says in the error message:
NoMethodError in ProfessorsController#show
undefined method `user_id=' for #<Review::ActiveRecord_Relation:0x007fed19228e28>
That's because where always returns a Relation, even if it finds only one
record.
I'm quite new to RoR. At first I used a sqlite3 database but migrated it to mysql. Everything worked fine with my application until I added a record to my database.
I can update my new records using the "irb" console.
I have a function in my controller that is called from a python script which updates a record.
Here's the function:
# GET /dd_bots/update
# param name, att
def update
obj = Object.all
obj = obj.select{ |o| o.name == params[:name] }
obj[0].update_attribute(:att, params[:att])
head :ok
end
However this function doesn't update the newly added records returning this error: NoMethodError (undefined method update_attribute' for nil:NilClass)
Obviously the record doesn't seem to be found...
Do you have any clue why is this happening?
Firstly, don't call your model Object: this could have disastrous consequences, as Object is the base class for practically every object in Ruby.
Secondly, the update_attribute is being called on the first element of obj, which is an array. You will get that error if the array contains no elements, i.e. if there are no objects where the name is the same as the name parameter being passed to the controller.
You can do this in a way that's less error prone:
def update
obj = Object.find_by_name(params[:name])
obj.update_attribute(:att, params[:att]) if obj
head :ok
end
If a record should exist, you might like to throw an exception if it doesn't. You can do this by adding a ! to the find_by_name method:
obj = Object.find_by_name!(params[:name]) # Could throw an ActiveRecord::RecordNotFound
This has the benefit of giving a HTTP 404 status code if the record doesn't exist, but acts in the same way otherwise.
This is the conventional way of doing that. Do substitute Object with your model name.
def update
obj = Object.find_by_name(params[:name]
if obj
obj.update_attribute(:att, params[:att])
end
head :ok
end
Does that work for you?
If not, try this in erb - Object.find_by_name('whatever_name') and see if your record actually exists or not.
I've got a helper in my ApplicationHelper file that works just fine:
def latest_issue
#issue = Issue.find(:all, :order => "id DESC", :limit => 1)
return #issue
end
After that, using #issue works just fine in any view, but considering that #issue has a column named message using #issue.message returns a No Method Error.
Any help would be fantastic! Cheers.
The issue instance variable is returning an array of objects not an instance. If you would like to select an attribute of an Issue object you need to return an instance of the object.
#issue = Issue.find(:last)
#issue.message
You may be trying to output all the message attributes of the Issue object, if that is the case you need to pass the #issue to an block
#issue.each do |issue|
issue.message
end
As Kyle C says, you're attempting to access the member message of an array of Issues, when you should be returning a single issue from your helper.
Assuming you're using Rails 3, A vastly improved version of your helper would be written this way:
def latest_issue
Issue.order(:id).last
end
A few notes on writing idomatic Ruby:
Avoid explicit return statements, and let the last statement be the return value of a method
Use the chainable methods like order(), where(), and limit() instead of passing arguments to find
I have the following which works great:
#request_thread = current_user.request_threads.new(params[:request_thread])
And I have this which works great:
#requestable = find_requestable
#request_thread = #requestable.request_threads.new(params[:request_thread])
But if I try the 2nd line with:
#request_thread = #requestable.current_user.request_threads.new(params[:request_thread])
With the current_user I get the following error:
NoMethodError (undefined method `current_user' for #<Photo:0x10f95c828>):
app/controllers/request_threads_controller.rb:52:in `create'
app/middleware/flash_session_cookie_middleware.rb:14:in `call'
What did I mess up on here?
Thanks
UPDATE - with find_requestable
# http://asciicasts.com/episodes/154-polymorphic-association
def find_requestable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
The error message tells you exactly whats wrong: current_user doesn't exist for the #requestable object, whatever that is.
current_user is most likely a function inherited from ApplicationController, or at least that's usually where it lives. It usually returns a User object according to the current session. But that isn't a built-in part of Rails, so we need more information if you want me to go into greater detail.
#requestable looks like a polymorphic model instance so it wouldn't be aware of the current session.
There's a bit of Rails magic happening here that I think is confusing you.
Both #requestable.request_threads and current_user.request_threads are helper functions that have been generated by Rails on those objects to save you time by filtering results and filling in values automatically.
I think, by the code you have shown us so far, that you are trying to associate current_user with the new request_thread you are creating. In that case, you can simple merge that into the attributes manually. Since I don't know what your models look like I can only guess at the field names:
#request_thread = #requestable.request_threads.new( params[:request_thread].merge(:user => current_user) )
Like I said, the chainable functions are merely for convenience. For instance, you could write it this way instead:
#request_thread = request_thread.new(params[:request_thread])
#request_thread.requestable = find_requestable
#request_thread.user = current_user