NoMethodError: undefined method `name' for :account:Symbol - ruby-on-rails

I am trying to query the following
Vehicle.where(:account.name => "").count
and I get this error:
NoMethodError: undefined method `name' for :account:Symbol
The associations between Vehicle and Account have been define on the model, and I user conventions. Why do I get this error?
Vehicle.rb
class Vehicle < ActiveRecord::Base
belongs_to :account
end
Account.rb
class Account < ActiveRecord::Base
has_many :vehicles
end
Schema
create_table "accounts", force: true do |t|
t.string "name"
...
end
create_table "vehicles", force: true do |t|
t.integer "account_id"
...
end

You can use the following:
Vehicle.joins(:account).where("accounts.name = ?", "").count
You can also search for blank fields with:
Vehicle.joins(:account).where("accounts.name <> ''").count

Error is raise because rails is considering account as a column, if you want to where condition for associated table then make join between them, like following
Vehicle.joins('account').where("account.name IS NULL").count

Related

NoMethodError: undefined method `title' for #<Ingredient:0x0000000005e6cf30>

I have come across this error a few times this week, but this time I have no idea what is wrong. I have an ActiveRecord Model called Ingredients
class CreateIngredients < ActiveRecord::Migration[5.2]
def change
create_table :ingredients do |t|
t.string :title , null: false
t.integer :availability
t.decimal :price, precision:15, scale: 2
t.timestamps
end
end
end
And this is the application record I have for it:
class Ingredient < ApplicationRecord
validates :title, presence: true
has_many :ingredient_categories
has_many :categories, through: :ingredient_categories
end
Now I try to create a new Ingredient on the irb but I get an error saying:
NoMethodError: undefined method 'title' for #Ingredient:0x0000000005e6cf30>
This is the exact output on the console:
irb(main):003:0> Ingredient.create!(title: 'Cheese Spread')
#=> ActiveModel::UnknownAttributeError: unknown attribute 'title' for Ingredient.
Can someone help me understand what I am doing wrong?
Try rails db:migrate if you have not added this migration and then use rails console.
What you probably did was rails db:migrate when you first created the table, but after you added the columns you did not and so when you went to create an Ingredient, it knew what the table was, thus why it could not go further than title.

Scope a Post with his association table

I would like to know how we can scope a Post with his association table ?
I explain what I want to do it will be more clear. I actually have a scaffold :ranch, and a scaffold :staff. And when I create a new Staff, I can choose to associated it with many ranches. So I have an other table to reference this association :ranch_staff.
So if I want to scope the staff to display only which are associated with the actual #ranch, how can I do that ?
Something like this should do the trick:
migration:
class Init < ActiveRecord::Migration
def change
create_table :ranches do |t|
t.string "name"
end
create_table :staffs do |t|
t.string "name"
end
create_table :ranches_staffs, id: false do |t|
t.belongs_to :ranch
t.belongs_to :staff
end
end
end
app/models/staff.rb:
class Staff < ActiveRecord::Base
has_and_belongs_to_many :ranches
end
app/models/ranch.rb:
class Ranch < ActiveRecord::Base
has_and_belongs_to_many :staffs
end
run in rails console:
staff1 = Staff.create(name: "staff1")
staff2 = Staff.create(name: "staff2")
staff3 = Staff.create(name: "staff3")
staff4 = Staff.create(name: "staff4")
ranch1 = Ranch.create(name: "ranch1")
ranch2 = Ranch.create(name: "ranch1")
staff1.ranches << ranch1
staff2.ranches << ranch1
staff3.ranches << ranch2
staff4.ranches << ranch2
Now you can access ranch1's staff by
ranch1.staffs
=> #<ActiveRecord::Associations::CollectionProxy [#<Staff id: 1, name: "staff1">, #<Staff id: 2, name: "staff2">]>
See association.

Nearly identical methods in PagesController produce an undefined method error in Rails 4

I have three tables in my Rails 4 app -- one for Game, Category, and Topic. Both Category and Topic have a column for :name, while Game includes information like starts_at for when a game begins.
In my PagesController, I can show data from both Game and Topic by using find_by with the params value:
topic = Topic.find_by_name(params[:topic])
#games = Game.for_topic(topic).upcoming.order(:starts_at)
This works fine.
What's weird is that when I use the same reasoning but with Category instead of Topic, like so:
category = Category.find_by_name(params[:category])
#games = Game.for_category(category).upcoming.order(:starts_at)
I receive an error message:
undefined method `for_category'
This is confusing to me since I am definitely defining category and the using it in my for_ expression. Am I making an error in my thinking?
Additional
CreateCategories Migration
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.belongs_to :topic, index: true
t.string :name, :null => false
t.timestamps
end
end
end
CreateTopics Migration
class CreateTopics < ActiveRecord::Migration
def change
create_table :topics do |t|
t.string :name, :null => false
t.timestamps
end
end
end
I think you setup the named scope for_topic in the Game model. But is missing the for_category, which is why it is failing.
Try setting the named scope for_category in Game model.

Querying the database passing multiple parameters rails

I have a user table and an activity table. The user has many activities. This is what i have in my users table:
class SorceryCore < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :surname
t.integer :previous_award
t.integer :chosen_award
t.string :email, :null => false
t.string :crypted_password
t.string :salt
t.timestamps
end
add_index :users, :email, unique: true
end
This is what I have in my activities table:
class CreateActivities < ActiveRecord::Migration
def change
create_table :activities do |t|
t.integer :activity_type
t.string :activity_name
t.string :approver_email
t.references :users, index: true, foreign_key: true
t.timestamps null: false
end
end
In my view I want to show the activity_name, where user_id = the current user's id, and where the the activity_type = 1. I'm not sure where to write this method or how to call it either. I have read through the following link but can't seem to get anything working. http://guides.rubyonrails.org/active_record_querying.html
I think I need to use something along the lines of this:
Activity.where("activity_type <= ?", 1).where("user_id <= ?", current_user.id)
But I'm not sure if this is supposed to go into a method in the controller or the model, and I'm not sure which controller or model it's supposed to go into
In the User model:
# user.rb
def activity_by_type(type = 1)
self.activities.where(activity_type: type).first
end
and then, you can call current_user.activity_by_type(<specify the type here>)
You can use the above method to get any of the activity type for the specified user, by specifying the type in the method call.
One advice I'll give though is to try and use the concept of enums to categorize your activity_type column in the activities table. An example on how, can be found here.
You simply have to query on the current_user.activities association:
#activities = current_user.activites.where(activity_type: "1")
You could also use a scope (which is what SunnyK recommended):
#app/models/user.rb
class User < ActiveRecord::Base
has_many :activities
scope :by_type, ->(type = 1) { activities.where(activity_type: type) }
end
--
If you only wanted to return a single record, you'd have to replace .where with .find_by:
#activity = current_user.activities.find_by activity_type: 1
--
Since you're using an enum, you may wish to use the built-in class method that you'd be able to call:
enum activity_type: [:sports, :photography]
#activity = current_user.activities.sports

How do I create a method to find out if a user is part of a group?

I am having a hard time creating a method to find out if a user is part of a group. There is a model for User, Group, and Membership. Below are two methods (of the many that I attempted but to no success).
How can I create a method to find out if a user is a member of a group? (I would like the method to produce a true or false result.)
def member?(group_1)
if Membership.where(user_id: self.id, group_id: group_1.id)
return true
else
return false
end
end
def membership?(group)
Membership.where(user_id: self.id, group_id: group.id)
end
Here are the attributes of the three different models:
create_table "groups", force: :cascade do |t|
t.string "name"
end
create_table "memberships", force: :cascade do |t|
t.integer "user_id"
t.integer "group_id"
end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "first_name"
t.string "last_name"
end
Here is the code in each respective model:
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class User < ActiveRecord::Base
has_many :memberships, dependent: :destroy
has_many :groups, through: :memberships
end
class Group < ActiveRecord::Base
has_many :memberships, dependent: :destroy
has_many :users, through: :memberships
end
In regards to you question create a method to find out if a user is a member of a group, This should work fine
In user.rb define an instance method
def membership?(group)
memberships.find_by(group: group).present?
end
This should work for you:
def member?(group)
groups.include?(group)
end
Your current membership? method is returning an array. If you append .any? to the end of it, it will return true or false.
def membership?(group)
Membership.where(user_id: self.id, group_id: group.id).any?
end
EDIT: dhouty's answer is the most precise - leaving this here just to explain why your original method wasn't working
You can do this in two clean ways. (You may either or both use the following)
1) app/models/user.rb
class User < ActiveRecord::Base
# ...
# ...
def member_of_group?(group)
groups.exists?(group)
end
end
2) app/models/groups.rb
class Group < ActiveRecord::Base
# ...
# ...
def has_user_member?(user)
users.exists?(user)
end
end
Then you can just use the methods like the following:
# If checking if a User object is member of a #group
#user.member_of_group?(#group)
=> returns true or false
# If checking if a Group object has a member #user
#group.has_user_member?(#user)
=> returns true or false
not the answer, but just saying:
def member?(group_1)
if Membership.where(user_id: self.id, group_id: group_1.id)
return true
else
return false
end
end
Membership.where will return [] unless it finds any data. For that, [] does equal true , that means - your true block will always be called! If you wanna stick with that where logic, you need to ask if the array is containing any data. [].any?
you dont need to write return since ruby is always returning the last value of anything.
// Edit towards your request by comment:
ya, you can go .where().any? but imageine the .where() will return a thousand datasets and you just need to know if there is just one...
We would call this "bad code".
The better solution would be to use find_by. Find_by returns the first matching element.
Membership.find_by(user_id: id, group_id. group_1.id)
the good thing about find_by is the fact, that it will return nil if nothing was found. That means you can do this
def member?(group_1)
!!Membership.find_by(user_id: id, group_id: group_1.id)
end
Find_by will return nil or the object, with !! you make the object to an expression of true

Resources