undefined method with has_many association - ruby-on-rails

I have 2 models with a one-to-many association: User and Recipe. the User class has_many :recipes while the Recipe class belongs_to :user. I've already run the migration, reloaded the rails console, and checked to make sure that user_id is a column in the recipes table. Still, I get an undefined method error when I try to append a recipe to a user:
2.0.0-p598 :047 > user.recipes << Recipe.first
NoMethodError: undefined method `recipes' for #<User:0x00000004326fa0>
here is the migration code (I've already run rake db:migrate):
class AddUserIdToRecipes < ActiveRecord::Migration
def change
add_column :recipes, :user_id, :integer
end
end
Here is the User model code:
class User < ActiveRecord::Base
has_one :profile
has_many :recipes
end
Here is the Recipe model code:
class Recipe < ActiveRecord::Base
validates_presence_of :title, :body
belongs_to :user
def long_title
"#{title} - #{published_at}"
end
end
Why does recipes still show up as an undefined method?

Try this on your console:
irb(main):007:0> user = User.new first_name: 'John', last_name: 'Doe'
=> #<User id: nil, first_name: "John", last_name: "Doe", created_at: nil, updated_at: nil>
irb(main):008:0> user.save
(0.1ms) begin transaction
SQL (0.6ms) INSERT INTO "users" ("created_at", "first_name", "last_name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2015-01-19 21:14:33.489371"], ["first_name", "John"], ["last_name", "Doe"], ["updated_at", "2015-01-19 21:14:33.489371"]]
(0.6ms) commit transaction
=> true
irb(main):009:0> r = Recipe.new name: 'oooohh awesome', description: 'my description goes here'
=> #<Recipe id: nil, name: "oooohh awesome", description: "my description goes here", created_at: nil, updated_at: nil, user_id: nil>
irb(main):010:0> r.save
(0.1ms) begin transaction
SQL (0.2ms) INSERT INTO "recipes" ("created_at", "description", "name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2015-01-19 21:15:16.548090"], ["description", "my description goes here"], ["name", "oooohh awesome"], ["updated_at", "2015-01-19 21:15:16.548090"]]
(1.2ms) commit transaction
=> true
irb(main):011:0> user.recipes << Recipe.first
Recipe Load (0.2ms) SELECT "recipes".* FROM "recipes" ORDER BY "recipes"."id" ASC LIMIT 1
(0.0ms) begin transaction
SQL (0.2ms) UPDATE "recipes" SET "updated_at" = ?, "user_id" = ? WHERE "recipes"."id" = 1 [["updated_at", "2015-01-19 21:15:49.181586"], ["user_id", 1]]
(1.3ms) commit transaction
Recipe Load (0.2ms) SELECT "recipes".* FROM "recipes" WHERE "recipes"."user_id" = ? [["user_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>]>
irb(main):012:0> user.save
(0.1ms) begin transaction
(0.0ms) commit transaction
=> true
irb(main):013:0> user.recipes
=> #<ActiveRecord::Associations::CollectionProxy [#<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>]>
irb(main):014:0> user.recipes.first
=> #<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>
irb(main):015:0>
you can see that Recipe.first has been inserted into user.recipes and its saved.
I made two models similar to yours, and have exactly the same setup as you. You can follow code above to write your controllers.

Related

Rails 4 ActiveRecords: Save multiple records at once with validation

Hi i have the following situation. I can save this array of hashes
products = [{
:name=> 0,
:key => 12345,
:label => "test1",
},{
:name=> 0,
:key => 12145,
:label => "test",
}]
at once with
products.map {|p| Product.new(p).save }
or
Product.create(products)
Product.create!(products)
but the all my uniqueness validations like
validates :key, presence: true, uniqueness: true
are ignored, using the rails console. I am able to save this hash multiple times. Does anyone has some advice? Thanks in advance!
SOLUTION
As simple as restarting my rails console. After that my logs look like the logs from #Akadisoft.
Also using this way:
products.map {|p| Product.new(p).save }
which return an array with booleans [false,true] either the record was saved or not, which is nice for further evaluation.
I have tried your exact solution and everything works as intented..
The first time I ran the command Product.create(products) I have the following result
=> #<ActiveRecord::Relation [#<Product id: 1, key: "12345", name: 0, label: "test1", created_at: "2015-12-09 19:21:01", updated_at: "2015-12-09 19:21:01">, #<Product id: 2, key: "12145", name: 0, label: "test", created_at: "2015-12-09 19:21:01", updated_at: "2015-12-09 19:21:01">]>
We can see that it created two products (id:1 and id:2).
Now the second I run the exact same command here is the result:
[#<Product id: nil, key: "12345", name: 0, label: "test1", created_at: nil, updated_at: nil>, #<Product id: nil, key: "12145", name: 0, label: "test", created_at: nil, updated_at: nil>]
irb(main):015:0>
We can see the ID is nil because it didn't save the products. I can also see in the console output that DB transaction were rollbacked.
I tried this on console and it only added one record.
14:42 $ rails c
Loading development environment (Rails 4.2.5)
2.2.2 :001 > products = [{:key =>1},{:key=>1}]
=> [{:key=>1}, {:key=>1}]
2.2.2 :002 > products.map {|p| Product.new(p).save }
(0.1ms) begin transaction
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."key" = 1 LIMIT 1
SQL (0.8ms) INSERT INTO "products" ("key", "created_at", "updated_at") VALUES (?, ?, ?) [["key", 1], ["created_at", "2015-12-09 19:42:32.488255"], ["updated_at", "2015-12-09 19:42:32.488255"]]
(0.4ms) commit transaction
(0.0ms) begin transaction
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."key" = 1 LIMIT 1
(0.0ms) rollback transaction
=> [true, false]
2.2.2 :003 > Product.all
Product Load (0.2ms) SELECT "products".* FROM "products"
=> #<ActiveRecord::Relation [#<Product id: 1, key: 1, created_at: "2015-12-09 19:42:32", updated_at: "2015-12-09 19:42:32">]>

Rails Updating attribute always inserts nil

Having an issue with a database update. At first I thought it might be related to Carrierwave but after this test I don't think so anymore.
Here I try and update the attribute in the rails console, only to have the image field return nil. But notice that the property_id field changes.
2.2.0 :004 > Propimage
=> Propimage(id: integer, property_id: integer, image: string, created_at: datetime, updated_at: datetime)
2.2.0 :005 > Propimage.last
Propimage Load (0.7ms) SELECT "propimages".* FROM "propimages" ORDER BY "propimages"."id" DESC LIMIT 1
=> #<Propimage id: 37, property_id: 5, image: nil, created_at: "2015-07-15 20:06:55", updated_at: "2015-07-15 20:22:30">
2.2.0 :006 > Propimage.last.update_attributes(image: 'Picture.jpg', property_id: 3)
Propimage Load (0.3ms) SELECT "propimages".* FROM "propimages" ORDER BY "propimages"."id" DESC LIMIT 1
(0.1ms) begin transaction
Propimage Load (0.2ms) SELECT "propimages".* FROM "propimages" WHERE "propimages"."id" = ? LIMIT 1 [["id", 37]]
SQL (0.5ms) UPDATE "propimages" SET "image" = ?, "property_id" = ?, "updated_at" = ? WHERE "propimages"."id" = ? [["image", nil], ["property_id", 3], ["updated_at", "2015-07-15 20:24:06.501042"], ["id", 37]]
(1.1ms) commit transaction
=> true
2.2.0 :007 > Propimage.last
Propimage Load (0.2ms) SELECT "propimages".* FROM "propimages" ORDER BY "propimages"."id" DESC LIMIT 1
=> #<Propimage id: 37, property_id: 3, image: nil, created_at: "2015-07-15 20:06:55", updated_at: "2015-07-15 20:24:06">
2.2.0 :008 >
And here I try to create a new entry
2.2.0 :009 > Propimage.new(image: 'Picture.jpg', property_id: 5).save
(0.2ms) begin transaction
SQL (1.0ms) INSERT INTO "propimages" ("image", "property_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["image", nil], ["property_id", 5], ["created_at", "2015-07-15 20:30:17.797735"], ["updated_at", "2015-07-15 20:30:17.797735"]]
(1.7ms) commit transaction
=> true
My next step is to recreate this table in the database. Any help is greatly appreciated.
class CreatePropimages < ActiveRecord::Migration
def change
create_table :propimages do |t|
t.references :property, index: true, foreign_key: true
t.string :image
t.timestamps null: false
end
end
end
propimage.rb
class Propimage < ActiveRecord::Base
belongs_to :property
mount_uploader :image, ImageUploader
end

Rails: Migration default value cannot be overwritten by create methods

I have an migration for new table:
class CreateContentCategories < ActiveRecord::Migration
def change
create_table :content_categories do |t|
t.string :title, default: '', null: false
t.timestamps null: false
end
end
end
When I try to create or find_or_create_by new records with options:
def self.assign_titles_to_app(titles, app)
# somewhere inside ( class scope )
title = 'movies'
content_category = find_by_title(title) || create(title: title)
puts "title: #{title} category: #{content_category.inspect}"
active record doesn't use my title
title: movies category: #<ContentCategory id: 1050, title: "", created_at: "2015-06-25 15:42:57", updated_at: "2015-06-25 15:42:57">
the same result for find_or_create_by:
title = 'movies'
content_category = find_or_create_by(title: title)
title: movies category: #<ContentCategory id: 1062, title: "", created_at: "2015-06-25 15:45:25", updated_at: "2015-06-25 15:45:25">
Documentation said:
:default - The column's default value. Use nil for NULL.
What is going wrong? how to fix it?
Info:
rails 4.2.1
activerecord 4.2.1
ruby 2.2.2
Update: I forgot about attr_accessible:
class ContentCategory < ActiveRecord::Base
# attr_accessible :title <- I forgot to add this line, oh
end
There's nothing wrong with your code, maybe you need to restart your app (and spring) or maybe the problem is in code that you haven't shown. Just to demonstrate, I added your exact code to a vanilla 4.2 app and:
[9] pry(main)> ContentCategory.assign_titles_to_app 1, 2
ContentCategory Load (0.2ms) SELECT "content_categories".* FROM "content_categories" WHERE "content_categories"."title" = ? LIMIT 1 [["title", "movies"]]
(0.1ms) begin transaction
SQL (0.7ms) INSERT INTO "content_categories" ("title", "created_at", "updated_at") VALUES (?, ?, ?) [["title", "movies"], ["created_at", "2015-06-25 16:31:59.192793"], ["updated_at", "2015-06-25 16:31:59.192793"]]
(0.5ms) commit transaction
title: movies category: #<ContentCategory id: 1, title: "movies", created_at: "2015-06-25 16:31:59", updated_at: "2015-06-25 16:31:59">
=> nil

Rails find_or_initialize_by not inserting data only "created_at", "updated_at"

I am trying to pull data from a csv and insert into database using rake. For some reason the insert statement is not including the data provided. As you can see in the Development.log file it searches for the correct record which does not exist then it tries to create the record. but only inserts date stamps for "created_at", "updated_at".
I am new to rails so it might be something very easy, but i was unable to find an answer online.I have been trying to figure out why its not working all day, any help is greatly appreciated
USDAData.csv
"ABELI","Abelia","abelia"
"ABGR4","Abelia ×grandiflora","glossy abelia"
"ABELM","Abelmoschus","okra"
"ABES","Abelmoschus esculentus","okra"
"ABMA9","Abelmoschus manihot",""
USDAData.rake
namespace :USDAData do
desc "import data from USDA to database"
task :import => :environment do
file = File.open(File.join(Rails.root, 'db', 'USDAData.csv'))
file.each do |line|
attrs = line.split(",")
#Accepted_Symbol = attrs[0].gsub!(/\A"|"\Z/, '')
#Scientific_Name = attrs[1].gsub!(/\A"|"\Z/, '').titleize
#Common_Name = attrs[2].gsub!(/\A"|"\Z/, '').titleize
p = Plant.find_or_create_by(Accepted_Symbol: #Accepted_Symbol, Scientific_Name: #Scientific_Name, Common_Name: #Common_Name)
end
end
end
development.log
[1m[36mPlant Load (0.4ms)[0m [1mSELECT "plants".* FROM "plants" WHERE "plants"."Accepted_Symbol" = ? AND "plants"."Scientific_Name" = ? AND "plants"."Common_Name" = ? LIMIT 1[0m [["Accepted_Symbol", "ABELI"], ["Scientific_Name", "Abelia"], ["Common_Name", "Abelia\n"]]
[1m[35m (0.2ms)[0m begin transaction
[1m[36mSQL (0.5ms)[0m [1mINSERT INTO "plants" ("created_at", "updated_at") VALUES (?, ?)[0m [["created_at", "2015-02-19 23:20:54.468007"], ["updated_at", "2015-02-19 23:20:54.468007"]]
[1m[35m (9.6ms)[0m commit transaction
[1m[36mPlant Load (0.2ms)[0m [1mSELECT "plants".* FROM "plants" WHERE "plants"."Accepted_Symbol" = ? AND "plants"."Scientific_Name" = ? AND "plants"."Common_Name" = ? LIMIT 1[0m [["Accepted_Symbol", "ABGR4"], ["Scientific_Name", "Abelia ×Grandiflora"], ["Common_Name", "Glossy Abelia\n"]]
[1m[35m (0.1ms)[0m begin transaction
[1m[36mSQL (0.3ms)[0m [1mINSERT INTO "plants" ("created_at", "updated_at") VALUES (?, ?)[0m [["created_at", "2015-02-19 23:20:54.482516"], ["updated_at", "2015-02-19 23:20:54.482516"]]
[1m[35m (9.8ms)[0m commit transaction
[1m[36mPlant Load (0.1ms)[0m [1mSELECT "plants".* FROM "plants" WHERE "plants"."Accepted_Symbol" = ? AND "plants"."Scientific_Name" = ? AND "plants"."Common_Name" = ? LIMIT 1[0m [["Accepted_Symbol", "ABELM"], ["Scientific_Name", "Abelmoschus"], ["Common_Name", "Okra\n"]]
plant.rb
class Plant < ActiveRecord::Base
attr_accessor :Accepted_Symbol, :Scientific_Name, :Common_Name
validates :Accepted_Symbol, presence: true, :null => false
validates :Scientific_Name, presence: true, :null => false
validates :Common_Name, presence: true
before_save :test
def test
puts "test: #{#Accepted_Symbol}"
end
end
schema.rb
ActiveRecord::Schema.define(version: 20150218210119) do
create_table "plants", force: :cascade do |t|
t.string "Accepted_Symbol"
t.string "Scientific_Name"
t.string "Common_Name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Rails Console > Plant.first(5)
>> Plant.first(5)
Plant Load (0.3ms) SELECT "plants".* FROM "plants" ORDER BY "plants"."id" ASC LIMIT 5
=> [#<Plant id: 1, Accepted_Symbol: nil, Scientific_Name: nil, Common_Name: nil, created_at: "2015-02-19 23:20:54", updated_at: "2015-02-19 23:20:54">,
#<Plant id: 2, Accepted_Symbol: nil, Scientific_Name: nil, Common_Name: nil, created_at: "2015-02-19 23:20:54", updated_at: "2015-02-19 23:20:54">,
#<Plant id: 3, Accepted_Symbol: nil, Scientific_Name: nil, Common_Name: nil, created_at: "2015-02-19 23:20:54", updated_at: "2015-02-19 23:20:54">,
#<Plant id: 4, Accepted_Symbol: nil, Scientific_Name: nil, Common_Name: nil, created_at: "2015-02-19 23:20:54", updated_at: "2015-02-19 23:20:54">,
#<Plant id: 5, Accepted_Symbol: nil, Scientific_Name: nil, Common_Name: nil, created_at: "2015-02-19 23:20:54", updated_at: "2015-02-19 23:20:54">]
The before_save outputs the symbol, thus adding to the confusion. The data is making it all the way to the active-record but then those attributes are dropped from the insert statement.
SOLVED:
The issue was attr_accessor :Accepted_Symbol, :Scientific_Name, :Common_Name in my Plant.rb model, as suggested by Jordan Dedels. Marked as answered.
attr_accessor should only be used for attributes you do not want to store in the database. Remove this line and it should work:
attr_accessor :Accepted_Symbol, :Scientific_Name, :Common_Name

Has_many :through reversed access?

Not exactly an error, but I think I am missing something important here..
class Team < ActiveRecord::Base
has_many :groups
has_many :users, :through => :groups
class User < ActiveRecord::Base
acts_as_authentic
has_many :groups
has_many :teams, :through => :groups
class Group < ActiveRecord::Base
belongs_to :user
belongs_to :team
So I can do something like:
user_test.teams << team_test
and I expect that after that I should be able to do something like:
team_test.users
it will list user_test among all others.. But it does not..
What am I missing?
Thanks!
EDIT::
ruby-1.9.3-p0 :001 > user_test = User.create
(0.0ms) SAVEPOINT active_record_1
(0.1ms) SELECT 1 FROM "users" WHERE "users"."persistence_token" = '6f2890df599776198476630fad3db57b62606339d7ec2c1e96cc4081919789fa0a7cac5ffaed6b8f61f28f3ff2abd6ca890eb623c1b2d6718328d10527fa1566' LIMIT 1
(0.0ms) ROLLBACK TO SAVEPOINT active_record_1
=> #<User id: nil, username: nil, email: nil, crypted_password: nil, password_salt: nil, persistence_token: "6f2890df599776198476630fad3db57b62606339d7ec2c1e96c...", created_at: nil, updated_at: nil>
ruby-1.9.3-p0 :002 > team_test = Team.create
(0.0ms) SAVEPOINT active_record_1
SQL (1.9ms) INSERT INTO "teams" ("created_at", "name", "personal", "project_id", "updated_at", "visible") VALUES (?, ?, ?, ?, ?, ?) [["created_at", Tue, 22 Nov 2011 23:09:28 UTC +00:00], ["name", nil], ["personal", false], ["project_id", nil], ["updated_at", Tue, 22 Nov 2011 23:09:28 UTC +00:00], ["visible", nil]]
(0.0ms) RELEASE SAVEPOINT active_record_1
=> #<Team id: 8, name: nil, created_at: "2011-11-22 23:09:28", updated_at: "2011-11-22 23:09:28", visible: nil, personal: false, project_id: nil>
ruby-1.9.3-p0 :003 > user_test.teams << team_test
(0.1ms) SAVEPOINT active_record_1
(0.0ms) RELEASE SAVEPOINT active_record_1
=> [#<Team id: 8, name: nil, created_at: "2011-11-22 23:09:28", updated_at: "2011-11-22 23:09:28", visible: nil, personal: false, project_id: nil>]
ruby-1.9.3-p0 :004 > user_test.teams
=> [#<Team id: 8, name: nil, created_at: "2011-11-22 23:09:28", updated_at: "2011-11-22 23:09:28", visible: nil, personal: false, project_id: nil>]
ruby-1.9.3-p0 :005 > team_test.users
User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "groups" ON "users"."id" = "groups"."user_id" WHERE "groups"."team_id" = 8
=> []
This is strange... Are user_test and team_test saved or only initialized?
1/ the both are saved:
user_test = User.create
team_test = Team.create
user_test.teams << team_test
user_test.teams # => team_test among others
team_test.users # => user_test among others
2/ only one is saved:
a) the saved model is the one which 'received' the other:
user = User.create
team = Team.new
user.teams << team
# team is saved automatically
user.teams # => team among others
team.users # => user among others (because team was saved automatically)
b) the saved model is the one which 'is received' by the other:
user = User.new
team = Team.create
user.teams << team
user.teams # => return team
team.users # => [] (empty array; the 'receiver' is not saved automatically)
3/ none is saved
user = User.new
team = Team.new
users.teams << team
user.teams # => team but not saved (i.e. id is nil)
team.users # => [] (empty array)
You might be in case 2.b or in case 3.

Resources