When I seed my database, I get this error: unknown attribute 'user' for Post.
My schema looks like this:
create_table "posts", force: :cascade do |t|
t.string "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "collection_id"
t.index ["collection_id"], name: "index_posts_on_collection_id"
t.index ["user_id"], name: "index_posts_on_user_id"
end
My seeds.rb file looks like this:
require 'faker'
10.times do |user|
User.create!(
name: Faker::Name.name,
birthday: '2019-09-04',
skin_type: 'Dry',
email: Faker::Internet.email,
password:Faker::Internet.password
)
end
users = User.all
puts "Users seeded"
50.times do
Post.create!(
user: users.sample,
body: Faker::Lorem.paragraphs
)
end
My creating Post migration file looks like this:
class CreatePosts < ActiveRecord::Migration[5.2]
def change
create_table :posts do |t|
t.string :body
t.timestamps
end
end
end
In my seeds.rb file, Post.create! cannot access the user attribute. Is this because the user attribute is not included in the CreatePosts migration file? Shouldn't this not matter since within the schema, posts and user_id are connected?
Based on your discussion on the comments, you need to add user association in the post model:
class Post < ApplicationRecord
belongs_to :user
end
Related
I have two tables User and UserToken. User has_one: token and UserToken belongs_to :user. I was under the impression this would add UserToken#User method to the UserToken class. However, I am getting:
undefined method 'user' for '#' with the
following 'UserToken.where(user_id: 1).user
Do I not understand the association correctly or have I not set it up right?
UsersController:
def get
user = UserToken.where(user_id: 1).user
render json: user.to_json
end
User Model:
class User < ApplicationRecord
has_one :user_token
end
UserToken Model:
class UserToken < ApplicationRecord
belongs_to :user
end
Migration:
def change
create_table :users do |t|
# This id comes from Auth0
t.datetime :date
t.timestamp :updated_at
t.timestamp :created_at
end
create_table :user_tokens do |t|
t.belongs_to :user
# This comes from plaid when a user signs in
t.string :token
t.timestamp :updated_at
t.timestamp :created_at
end
end
Schema:
ActiveRecord::Schema.define(version: 2019_09_19_004350) do
create_table "user_tokens", force: :cascade do |t|
t.bigint "user_id"
t.string "token"
t.datetime "updated_at"
t.datetime "created_at"
t.index ["user_id"], name: "index_user_tokens_on_user_id"
end
create_table "users", force: :cascade do |t|
t.datetime "date"
t.datetime "updated_at"
t.datetime "created_at"
end
end
What you want is:
UserToken.where(user_id: 1).first.user
or better yet:
UserToken.find_by(user_id: 1).user
You're getting the "undefined method" error because #where returns an ActiveRecord::Relation and an ActiveRecord Relation has no #user method.
UserToken.where(user_id: 1).class.name
#=> "ActiveRecord::Relation"
UserToken.where(user_id: 1).first.class.name
#=> "UserToken"
I have a User model and a Project model.
Users can create many projects, while a project has one owner and can have many members.
#app/models/user.rb
class User < ApplicationRecord
has_secure_password
has_many :projects
has_and_belongs_to_many :projects
end
#app/models/project.rb
class Project < ApplicationRecord
belongs_to :user
has_and_belongs_to_many :users
end
And this will create a database tables something like this:
create_table "projects", force: :cascade do |t|
t.string "name"
t.integer "user_id" #id of the owner of the projects
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_projects_on_user_id"
end
create_table "projects_users", force: :cascade do |t|
t.integer "user_id" #id of the member of the project
t.integer "project_id" #project that the member joined
t.index ["project_id"], name: "index_projects_users_on_project_id"
t.index ["user_id"], name: "index_projects_users_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Where the projects_users table is the junction/bridge table created for has_and_belongs_to_many association.
But whenever I run a test using rspec and shoulda only one of them succeeds the other one fails since in the user.rb file :projects are defined twice.
#spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, :type => :model do
context 'associations' do
it { should have_many(:projects) } #error
it { should have_and_belong_to_many(:projects) } #success
end
end
The error is Failure/Error: it { should have_many(:projects) }
Expected User to have a has_many association called projects (actual association type was has_and_belongs_to_many)
#spec/models/project_spec.rb
require 'rails_helper'
RSpec.describe Project, :type => :model do
context 'associations' do
it { should belong_to(:user) } #success
it { should have_and_belong_to_many(:users) } #success
end
end
How can I test many associations in one model correctly?
As per the description shared , I was able to test has_many using the below mentioned snippet:
RSpec.describe User, :type => :model do
context 'associations' do
it "should have many projects" do
subject { described_class.new }
assc = described_class.reflect_on_association(:projects)
expect(assc.macro).to eq :has_many
end
end
end
Well the answer for the part of has_man_belongs_to_many just change for something like this:
RSpec.describe Project, :type => :model do
context 'associations' do
it 'should have many and belongs to many Projects' do
subject {described_class.new }
response = described_class.reflect_on_association(:projects)
expect(assc.macro).to eq :has_and_belongs_to_many
end
end
end
I have three tables user, event, expected_event
My event are scrapped (every day with a rake task) from another
website
A user can create expected_event
So What I want to do is:
When a new event is found I want it to be compared to the Users expected_event...
If an event matches to any users expected_event then the users receive an email with the matching event (event.department, event.location_name)
I want to compare event.department to expected_event.department
I don't know how to do this...
expected_event.rb
class ExpectedEvent < ApplicationRecord
belongs_to :user
validates :department, presence: true
end
user.rb
class User < ApplicationRecord
has_many :expected_events
end
In the event model I have some methode to retreive city_name, location_nameand department
class Event < ApplicationRecord
def department
self.city[/\(.*?\)/].gsub(/[()]/, "").to_i
end
def city_name
self.city[/^[^\(]+/].rstrip!
end
def location_name
self.city[/\|(.*)/].gsub("|", "").strip
end
end
schema.rb
ActiveRecord::Schema.define(version: 20171210203403) do
create_table "events", force: :cascade do |t|
t.datetime "date"
t.string "city"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "nickname"
####
end
create_table "expected_events", force: :cascade do |t|
t.integer "department"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_expected_events_on_user_id"
end
end
EDIT
Is it correct if I add something like this to my user model?
has_many :matching_events, through: :events, source: :expected_events
When a new event is created, why don't you just query for ExpectedEvent records with matching paramters. Something like
event = Event.create(event_params)
if ExpectedEvent.where(city: event.city, ...).any?
#send email to user about the event
end
I'm trying to seed an application database, but I'm getting the following error:
ActiveRecord::AssociationTypeMismatch: Role(#97332160) expected,
got Fixnum(#76482890)
Here is the part of my schema.rb concerning the two table related to the problem:
create_table "roles", force: :cascade do |t|
t.string "role", limit: 50, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "first_name", limit: 100, null: false
t.string "surname", limit: 100, null: false
t.string "email", limit: 255
t.integer "role_id", limit: 11
t.string "password", limit: 150
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["first_name"], name: "index_users_on_first_name", using: :btree
add_index "users", ["role_id"], name: "index_users_on_role_id", using: :btree
add_index "users", ["surname"], name: "index_users_on_surname", using: :btree
add_foreign_key "users", "roles"
And here are my seeds.rb commands:
rl = Role.create(role: "root")
User.create(first_name: "Edvaldo", surname: "Silva de Almeida Júnior", email: "edvaldo#my.domain.com", role_id: rl.id, password: "my_password")
rl = Role.create(role: "admin")
User.create(first_name: "Daiely", surname: "Fanchin", email: "daiely#my.domain.com", role_id: rl.id, password: "other_password")
rl = Role.create(role: "user")
User.create(first_name: "César", surname: "Silva", email: "cesar#my.domain.com", role_id: rl.id, password: "yet_other_password")
I found a question where the accepted answer suggested I should do something like:
rl = Role.create(role: "root")
User.create(first_name: "Edvaldo", surname: "Silva de Almeida Júnior", email: "edvaldo#my.domain.com", role_id: Role.find(rl.id), password: "my_password")
I tried that, but got the same error! Besides, I'm using the role_id as association, not the role itself. So, as far as I'm concerned, it should receive a Fixnum, not a Role.
add_foreign_key "users", "roles" this will add role_id column to users no required to separately write t.integer "role_id", limit: 11
there should be some associations
class User < ActiveRecord::Base
belongs_to :role
end
and
create_table "users", force: :cascade do |t|
t.string "first_name", limit: 100, null: false
t.string "surname", limit: 100, null: false
t.string "email", limit: 255
t.reference "role", index: true
t.string "password", limit: 150
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "users", "roles", column: :role_id
hope it might solve it.
I had added a method set_default_role to my User model.
class User < ActiveRecord::Base
has_one :role
after_initialize :set_default_role, :if => :new_record?
def set_default_role
if User.count == 0
self.role ||= 1
else
self.role ||= 2
end
end
end
But this method was wrong and as soon as I rewrote it as
def set_default_role
if User.count == 0
self.role_id ||= 1
else
self.role_id ||= 2
end
end
my seeding worked fine.
So, the problem was the fact I was tryind (inside this method) to set a Role to a Fixnum.
This serves as an advice to Rails newbies: Seeding is not just forcing something to your database. It is a full evaluation of your model and sometimes an error may be caused by the execution of some method, not just by the values you try to load.
The problem you have is simple:
role_id: Role.find(rl.id)
.find() returns a Role object.
Your create method is expecting a foreign_key (integer) (role_id: [int]).
The simple fix would be:
User.create(... role_id: Role.find(rl.id).id ...)
.. or ...
User.create(... role_id: rl.id ...)
... or even better ...
User.create(... role: rl ...)
--
Fix
The real fix would either to set a default in your database, or manually set the role_id, as you have in your submitted answer.
I would strong recommend using the database default because then it doesn't matter what happens in your app - your database will always "default" to the role you set:
$ rails g migration SetDefaultForRole
$ db/migrate/set_default_for_role_____.rb
class SetDefaultForRole < ActiveRecord::Migration
def change
change_column :users, :role_id, :integer, default: 0
end
end
$ rake db:migrate
The downside to this would be that this integer default would be set (unless you changed your db again). Whilst not a problem in itself, it would create an antipattern for your Role model (IE you can create any role, as long as it's after the initial one you made).
--
The other way would be to set the Role for the user.
You have this already; you could clean it up:
#app/models/user.rb
class User < ActiveRecord::Base
before_create :set_role, if: Proc.new { |m| m.role_id.blank? }
private
def set_role
self.role_id = "1" if User.count == 0
end
end
I need some help with polymorphic associations. Below is my structure:
class Category < ActiveRecord::Base
has_ancestry
has_many :categorisations
end
class Categorisation < ActiveRecord::Base
belongs_to :category
belongs_to :categorisable, polymorphic: true
end
class classifiedAd < ActiveRecord::Base
belongs_to :user
has_one :categorisation, as: :categorisable
end
And here is my schema.rb
create_table "classifiedads", force: true do |t|
t.string "title"
t.text "body"
t.decimal "price"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "classifiedads", ["user_id"], name: "index_classifiedads_on_user_id", using: :btree
create_table "categories", force: true do |t|
t.string "name"
t.string "ancestry"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "categories", ["ancestry"], name: "index_categories_on_ancestry", using: :btree
create_table "categorisations", force: true do |t|
t.integer "category_id"
t.integer "categorisable_id"
t.string "categorisable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
It seems like the associations is correct as when I'm in the console I can do the appropriate commands and all seems to return the right results, for example: Category.first.categorisations or ClassifedAd.first.categorisation. But what I don't understand is saving the association from the Create and editing the record via the Update actions. I'm using simple_form to create my forms and when looking at the params I get the below:
{"title"=>"Tiger",
"body"=>"Huge Helicopter",
"price"=>"550.0",
"categorisation"=>"5"}
and this fails to update or even create as I get this error : Categorisation(#70249667986640) expected, got String(#70249634794540) My controller actions code are below:
def create
#classified = Classifiedad.new(classifiedad_params)
#classified.user = current_user
#classified.save
end
def update
#classified.update(classifiedad_params)
end
def classifiedad_params
params.require(:classifiedad).permit(:title, :body, :price)
end
I think it has something to do with the params as categorisation should be within a sub hash of results, is this right? Also, I need to do something extra within the actions, but what? What the params[:categorisation] value needs to do is save the number into the Categorisations.category_id table column and also save the polymorphic association. This table will be used across other models, which will also be a has_one association, as the user will only be able to select one category for each record. I really hope someone can help me here as the more I look into it the more I get confused :S Please let me know if you ned anymore info from me.
I'm using Rails 4 and Ruby 2
EDIT 2
I managed to get something working but I'm still not sure if its right. Below is the update code for the Create and Update actions. Would be good to know if there is a better way of doing this?
def create
#classified = Classifiedad.new(classifiedad_params)
#classified.user = current_user
**** NEW
cat = Categorisation.new(category_id: params[:classified][:categorisation])
#classified.categorisation = cat
**** END NEW
#classified.save
end
def update
**** NEW
#classified.categorisation.update_attribute(:category_id, params[:classified][:categorisation])
**** END NEW
#classified.update(classifiedad_params)
end