Undefined method in professors controller - ruby-on-rails

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.

Related

How to fix error with has_and_belongs_to_many creation in rails

I want to create a record in join table but rails shows me two errors in two situation, and I don't want to generate a third model.
#channel = Channel.find(params[:channel_id])
if #channel.users.create!(channel_id: params[:channel_id], user_id: params[:user_id])
flash[:success] = "U Succeed:)"
redirect_to request.referrer
else
flash[:danger] = "U Nit Succeed:H"
redirect_to request.referrer
end
second situation
if Channel.users.create!(channel_id: params[:channel_id], user_id: params[:user_id])
flash[:success] = "U Succeed:)"
redirect_to request.referrer
else
flash[:danger] = "U'r Not Succeed:H"
redirect_to request.referrer
end
I want to save attrs in join table. According to rails official site guide, what's wrong?
First error:
unknown attribute 'channel_id' for User.
Second error:
undefined method `users' for Class:0x00007feaa0312058
I am assuming that you have associations like these:
class User < ActiveRecord::Base
has_and_belongs_to_many :channels
end
class Channel < ActiveRecord::Base
has_and_belongs_to_many :users
end
Now you are trying to do like this:
#channel.users.create!(channel_id: params[:channel_id], user_id: params[:user_id])
This will try to create a new User class object as there is no Model in between you just have a mid table. Instead you can do it like this:
# If you don't have the user object already
user = User.find params[:user_id]
# This will create a record in the mid table
#channel.users << user
This will create a new record in the mid table and the existing records will also exist as it is. And if you do like this:
#channel.users = user
This will delete all the existing associated user records from the mid table for this channel and add a new associated record with this user.
And when you try doing like this:
Channel.users.create!(channel_id: params[:channel_id], user_id: params[:user_id])
This is not valid at all because the class Channel doesn't have any direct relation with the User but an instance of Channel class may be associated with instances of User class.
For the first scenario i would suggest you should do it like
#channel.user_ids = #channel.user_ids + [params[:user_id]]
it will create join table records, you can surely try optimised approach for this as you see fit.
you can use push or << method instead of create : Channel.users.push(attrs) or Channel.users << (attrs) and second answer in good too but .ids not very readable
or you can find channel by id and use it : channel.users.create(attrs)
see api.rubyonrails.org and search has_and_belongs_to_many methods in searchbar

Undefined method update when updating a record in Rails

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

Display user profile_name knowing user_id

I have added an updated_by attribute to my guideline model which stores the user_id of the person who updated the guideline. I'd like to display this in my show view as the profile_name of the person who updated_by
in guidelines_controller.rb:
def update
#guideline = Guideline.find(params[:id])
respond_to do |format|
if #guideline.update_attributes(params[:guideline])
#guideline.update_attribute(:updated_by, current_user.id)
This seems to work fine and allocated the current user's id to updated_by.
def show
#guideline = Guideline.find(params[:id])
#created = #user.where(:id=>#guideline.updated_by).first.profile_name
Then my show view
<%= #created %>
The error is
NoMethodError (undefined method `where' for nil:NilClass):
app/controllers/guidelines_controller.rb:137:in `show'
How can I get the profile name from the updated_by id?
You need to call the finder as a class method rather than an object method.
#created = User.where(:id => #guideline.updated_by ).first.profile_name
Or cleaner
#created = User.find(#guideline.updated_by).profile_name
It's also possible you may need to search by #guideline.updated_by.id instead of #guideline.updated_by. In that case it would be:
#created = User.find(#guideline.updated_by.id).profile_name
This line:
#created = #user.where(:id=>#guideline.updated_by).first.profile_name
should read:
#created = User.where(:id=>#guideline.updated_by).first.profile_name
where is a class method on the User model. #user (usually) refers to an instance of a user, which you haven't instantiated yet, in this case. (It is nil; that's why you're getting the NilClassError.)
An even cleaner version of this line would be:
#created = User.find(#guildeline.updated_by).profile_name
Since User.find finds the user for a given user_id.
The error is due to the fact that you call where on #user, not on User. Just call
#created = User.where(:id=>#guideline.updated_by).first.profile_name
Not sure if that's the only problem, but let's deal with them one-by-one.

Rails 3: where query issue

I am learning about 'where' in Rails 3 and I am wondering why my code is giving me a NoMethod Error.
def create
#get form values from 'new' page
#post = Post.new(params[:post])
#search for the inventory item with the sku code the user typed in the form
#item = Inventory.where(:sku_code => #post.sku_code)
#set post variable to a variable from the row with the sku code
#post.detail = #item.detail
#post.save
end
By searching the SKU, I want to retrieve the other variables in the same id and set them to my #post variable. Anyone able to give me a hand?
Assuming that SKU code is unique, you got to do it like this
#post = Post.new(params[:post])
#post.detail = Inventory.where(:sku_code => #post.sku_code).first.try(:detail)
first will fetch the first (and possibly only) record from the database. try will try to fetch detail if the returned Inventory was not nil.
Check this blog post to learn more about try method.

random loop with conditions in rails

I have a feature called "Browse" that allows users to browse through random profiles. When a user clicks on "browse" they are immediately taken to a users profile that they are NOT already friends with. What should my controller look like?
Right now I've got:
def browse
#users = User.all.offset(rand(current_user.matches.count))
#users.each do |user|
if !current_user.friends.include?(user)
#user = user
return
end
end
end
However that doesn't seem to be working. Any advice? I am admittedly bad with blocks, it seems!
You could try something like this
def browse
#user = (User.all - current_user.friends).sample
end
A better version would be
def browse
#user = User.where('id not in (?)', current_user.friends.map(&:id))
.offset(rand(current_user.matches.count)).limit(1)
end
Also, if you are too concerned about performance, instead of using the offset technique, better use the randumb gem to fetch the random record. It uses database specific functions for selecting random records, if available.
Add an extra method to your User, something like this:
def random_stranger
self.class.where(%Q{
id not in (
select friend_id
from friends
where user_id = ?
}, self.id).
order('random()').
limit(1).
first
end
Then in your controller:
def browse
#user = current_user.random_stranger
end
If your database doesn't know how to optimize that not in then you could replace it with a LEFT OUTER JOIN combined with WHERE friend_id is null.

Resources