List of relationship between models:
class ErrorScope < ActiveRecord::Base
belongs_to :server
has_many :scope_to_fixflow_map
attr_accessible :id, :server_id, :error_codes, :scoping_method, :priority, :error_codes_is_wildcard_match
serialize :error_codes
.....
end
class ScopeToFixflowMap < ActiveRecord::Base
belongs_to :error_scope
attr_accessible :id, :server_id, :error_scope_id, :path, :fixflow_class_name
......
end
class Server < ActiveRecord::Base
has_many :error_scopes
......
end
schema.rb
create_table "error_scopes", :force => true do |t|
t.integer "server_id", :limit => 8, :null => false
t.text "error_codes", :null => false
t.text "scoping_method"
t.integer "priority", :null => false
t.boolean "error_codes_is_wildcard_match", :default => false
end
create_table "scope_to_fixflow_maps", :force => true do |t|
t.integer "server_id", :limit => 8, :null => false
t.integer "error_scope_id", :limit => 8, :null => false
t.string "path"
t.string "fixflow_class_name", :null => false
end
Now i have a sql query which gives me desired output:
SELECT fixflow_class_name
FROM error_scopes s
join scope_to_fixflow_maps m on s.id=m.error_scope_id
join servers serv on serv.id=s.server_id
where error_codes regexp 'error_scope_test'
and path = 'x'
and assettag = 'y'
What I tried so far. It works
ErrorScope.where("error_codes like ?", "%error_scope_test\n%").select {|tag| tag.server.assettag == "y"}[0].scope_to_fixflow_map.select {|y| y.path == "x"}[0].fixflow_class_name
using joins
ErrorScope.joins(:server, :scope_to_fixflow_map).where("error_codes LIKE ?", "%error_scope_test%").select {|tag| tag.server.assettag == "y"}[0].scope_to_fixflow_map.select {|y| y.path == "x"}[0].fixflow_class_name
I am sure there must be better way to do this query??
Something like this:
ErrorScope.joins(:server, :scope_to_fixflow_map)
.where("error_codes LIKE ?", "%error_scope_test%")
.where("servers.assettag='y'")
.where("scope_to_fixflow_maps.path='x'")
.select("scope_to_fixflow_maps.fixflow_class_name")
Not the rails way but quick and dirty:
ActiveRecord::Base.execute("SELECT fixflow_class_name
FROM error_scopes s
join scope_to_fixflow_maps m on s.id=m.error_scope_id
join servers serv on serv.id=s.server_id
where error_codes regexp 'error_scope_test'
and path = 'x'
and assettag = 'y'")
Returns back an array of hashes that you can work with
Related
I am newbie to Rails. Now I have these files and a 'jobs.csv' file.
company.rb
class Company < ApplicationRecord
has_many :jobs, dependent: :destroy
end
job.rb
class Job < ApplicationRecord
belongs_to :company
def self.jobs_import
jobs = []
columns = [:title, :level, :salary, :description, :short_des, :requirement, :category, :company_id]
CSV.foreach(Rails.root.join("lib", "jobs.csv"), headers: true) do |row|
jobs << {title: row["name"], level: row["level"], salary: row["salary"], description: row["description"], short_des: row["benefit"], requirement: row["requirement"], category: row["type"]}
end
Job.import columns, jobs
end
end
Company migration files
create_table :companies do |t|
t.string :name
t.string :email, unique: true
t.text :description
t.string :address
t.string :company_code
t.timestamps
end
Job migration file
create_table :jobs do |t|
t.string :title
t.string :level
t.string :salary
t.string :other_salary
t.text :description
t.text :short_des
t.text :requirement
t.integer :category
t.datetime :post_date
t.datetime :expiration_date
t.references :company, foreign_key: true
t.timestamps
end
Now I want to import data to Job table that references to Job table. Please help me! Thanks!
UPDATE
Edit job.rb
jobs << {title: row["name"], level: row["level"], salary: row["salary"], description: row["description"], short_des: row["benefit"], requirement: row["requirement"], category: row["type"], company_id: Company.find_by(company_code: row["company id"])&.id}
Ok guys, this might be a little bit confusing so stick with me. Let me start by introducing my tables. Basically I created four tables upon migration.
Students
Teachers
Subjects
Admin User
Here are my migration files:
Students:
def up
create_table :students, :id => false do |t|
t.integer "student_id",:primary_key => true
t.string "first_name", :limit => 25
t.string "last_name", :limit => 50
t.string "email", :default => ' ', :null => false
t.string "birthday"
t.string "subjects"
t.string "teachers"
t.string "username", :limit => 25
t.string "password_digest"
t.timestamps
end
Teachers:
def up
create_table :teachers, :id => false do |t|
t.integer "teacher_id", :primary_key => true
t.string "first_name"
t.string "last_name"
t.string "email", :default => ' ', :null => false
t.string "birthday"
t.string "subjects"
t.string "username", :limit => 25
t.string "password_digest"
t.timestamps
end
Subjects:
def up
create_table :subjects, :id => false do |t|
t.integer "subject_id", :primary_key => true
t.string "subject_name"
t.timestamps
end
end
Admin Users:
def up
create_table :admin_users, :id => false do |t|
t.integer "admin_user_id", :primary_key => true
t.string "username", :limit => 25
t.string "password_digest"
t.timestamps
end
end
So now let me get through the explanation. Basically:
one student can have many teachers
one teacher can have many students
one student can have many subjects
one teacher can teach many subjects
the admin can access all of this (create, edit, delete)
I created this fields and set them up on my models like this:
class Student < ApplicationRecord
has_and_belongs_to_many :subjects
has_and_belongs_to_many :teachers
has_many :admin_users
has_secure_password
self.primary_key = :student_id
end
class Teacher < ApplicationRecord
has_and_belongs_to_many :subjects
has_and_belongs_to_many :students
has_many :admin_users
has_secure_password
end
class Subject < ApplicationRecord
has_and_belongs_to_many :students
has_and_belongs_to_many :teachers
has_many :admin_users
# scope :search, lambda { |query| where(["name LIKE ?", "%#{query}%"])}
end
class AdminUser < ApplicationRecord
has_secure_password
scope :newest_first, lambda { order("created_at ASC") }
scope :oldest_first, lambda { order("created_at DESC") }
# scope :search, lambda { |query| where(["name LIKE ?", "%#{query}%"])}
end
Now I manually inserted data on mysql data record and then tried to pull up the records for student's subjects and teachers form fields.
How can I manage my database effectively esp teachers, students, and subjects??? Is there anything I need to do first to correlate the tables I have? Please help. Sorry for the long post. I am a newbie here. Appreciate your explanation (layman's term) and answers.
Check my models. Do I need to create a separate table to correlate teachers, students, and subjects?
Side Note: When I pull up my students and teachers field it gives me an error ActiveRecord_Associations_CollectionProxy:0x007f9c504361d0 ERROR.
I think this relation should work in your case:
Students:
def up
create_table :students, :id => false do |t|
t.integer "student_id",:primary_key => true
t.string "first_name", :limit => 25
t.string "last_name", :limit => 50
t.string "email", :default => ' ', :null => false
t.string "birthday"
t.string "subjects"
t.string "username", :limit => 25
t.string "password_digest"
t.timestamps
end
end
Ref: Generating auto increment with sequence 1001
Teachers:
def up
create_table :teachers, :id => false do |t|
t.integer "teacher_id", :primary_key => true
t.string "first_name"
t.string "last_name"
t.string "email", :default => ' ', :null => false
t.string "birthday"
t.string "subjects"
t.string "username", :limit => 25
t.string "password_digest"
t.timestamps
end
end
Subjects:
def up
create_table :subjects, :id => false do |t|
t.integer "subject_id", :primary_key => true
t.string "subject_name"
t.timestamps
end
end
Enrolled Subjects:
def up
create_table :enrolled_subjects, :id => false do |t|
t.integer "subject_id"
t.integer "teacher_id"
t.integer "student_id"
end
end
Model:
class Student < ApplicationRecord
has_many :enrolled_subjects
has_many :subjects, through: :enrolled_subjects
has_many :teachers, through: :enrolled_subjects
def teacher_names
self.teachers.map(&:first_name).join(", ")
end
end
class Teacher < ApplicationRecord
has_many :enrolled_subjects
has_many :subjects, through: :enrolled_subjects
has_many :students, through: :enrolled_subjects
end
class Subject < ApplicationRecord
has_many :enrolled_subjects
has_many :students, through: :enrolled_subjects
has_many :teachers, through: :enrolled_subjects
end
class EnrolledSubject < ActiveRecord::Base
belongs_to :student, foreign_key: :student_id
belongs_to :subject, foreign_key: :subject_id
belongs_to :teacher, foreign_key: :teacher_id
end
Example Repository
I am working on a migration and I remove the default 'id' for each table. I created a special field instead 'student_id' and I want to make it auto increment starting with 1001.
Here is my code:
class CreateStudents < ActiveRecord::Migration[5.0]
def up
create_table :students, :id => false do |t|
t.integer "student_id"
t.string "first_name", :limit => 25
t.string "last_name", :limit => 50
t.string "email", :default => ' ', :null => false
t.string "birthday"
t.string "subjects"
t.string "teachers"
t.string "username", :limit => 25
t.string "password_digest", :limit => 40
t.timestamps
end
execute "CREATE SEQUENCE students_student_id_seq OWNED BY students.student_id INCREMENT BY 1 START WITH 1001"
end
def down
drop_table :students
execute "DELETE SEQUENCE students_student_id_seq"
end
end
I got the ff error:
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SEQUENCE students_student_id_seq OWNED BY students.student_id INCREMENT BY 1 STA' at line 1
How to auto a custom id increment with starting value in Ruby on Rails 5?
execute "CREATE SEQUENCE students_student_id_seq OWNED BY students.student_id INCREMENT BY 1 START WITH 1001"
The above is Postgresql syntax and your database seems to be MySQL.
Anyway, you can achieve what you want by setting student_id as a primary key and then updating the increment starting value.
def change
create_table :students, :id => false do |t|
t.integer "student_id", primary_key: true
t.string "first_name", :limit => 25
t.string "last_name", :limit => 50
t.string "email", :default => ' ', :null => false
t.string "birthday"
t.string "subjects"
t.string "teachers"
t.string "username", :limit => 25
t.string "password_digest", :limit => 40
t.timestamps
end
reversible do |dir|
dir.up { execute "ALTER TABLE students AUTO_INCREMENT = 1000" }
end
end
I'm trying to make an application to store played FIFA games.
I'm having some trouble setting up the right associations.
I have 2 models at this time, User and Game.
SCHEMA:
ActiveRecord::Schema.define(version: 20160402112419) do
create_table "games", force: :cascade do |t|
t.integer "home_team_user_id"
t.integer "away_team_user_id"
t.string "home_score"
t.string "away_score"
t.integer "winner_id"
t.integer "loser_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "games_users", id: false, force: :cascade do |t|
t.integer "user_id"
t.integer "game_id"
end
add_index "games_users", ["user_id", "game_id"], name: "index_games_users_on_user_id_and_game_id"
create_table "users", force: :cascade do |t|
t.string "username"
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
MODELS:
class Game < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :games
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
As you can see the "Games" table has 2 corresponding ID's:
home_team_user_id
away_team_user_id
These will store the user_id from the Users table, this is needed to calculate who's the winner corresponding with the score.
Console results:
irb(main):001:0> Game.last
Game Load (0.0ms) SELECT "games".* FROM "games" ORDER BY "games"."id" DESC LIMIT 1
=> #<Game id: 1, home_team_user_id: 1, away_team_user_id: 1, home_score: "1", away_score: "2", winner_id: 1, loser_id: 1, created_at: "2016-04-02 12:27:26", updated_at: "2016-04-02 12:27:26">
irb(main):002:0> game = Game.find(1)
Game Load (0.5ms) SELECT "games".* FROM "games" WHERE "games"."id" = ? LIMIT 1 [["id", 1]]
=> #<Game id: 1, home_team_user_id: 1, away_team_user_id: 1, home_score: "1", away_score: "2", winner_id: 1, loser_id: 1, created_at: "2016-04-02 12:27:26", updated_at: "2016-04-02 12:27:26">
irb(main):003:0> game.users
User Load (0.5ms) SELECT "users".* FROM "users" INNER JOIN "games_users" ON "users"."id" = "games_users"."user_id" WHERE "games_users"."game_id" = ? [["game_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy []>
I'm thinking now that the User.id needs to be linked to each individual corresponding id from the Games table.
How can I set this up? Do I need to use the has_many :through association?
UPDATE:
Could it be as simple as:
class User < ActiveRecord::Base
has_many :games, :foreign_key => "home_team_user_id"
has_many :games, :foreign_key => "away_team_user_id"
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
class Game < ActiveRecord::Base
belongs_to :user, :foreign_key => "home_team_user_id"
belongs_to :user, :foreign_key => "away_team_user_id"
end
Because actually a User has many games but in that game he only has one team, the home or away team. In this logic I assigned the user_id to one of the custom foreign fields.
You can achieve this like :
class User < ActiveRecord::Base
has_many :home_games, class_name: 'Game', foreign_key: 'home_team_user_id'
has_many :away_games, class_name: 'Task', foreign_key: 'away_team_user_id'
end
class Game < ActiveRecord::Base
belongs_to :home_user, class_name: "User", foreign_key: "home_team_user_id"
belongs_to :away_user, class_name: "User", foreign_key: "away_team_user_id"
# Rails anticipate foreign keys itself so, addig `foreign_keys` is not
# necessary in this class as we've already mentioned `belongs_to :home_user`
end
FIXED BY:
changing model names to match rails naming conventions
I'm getting the following error when I try to join a skill to a user:
irb(main):006:0> user.skills << skill
NameError: uninitialized constant Users::Skill
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/activerecord-3.1.3/lib/active_r
ecord/base.rb:1341:in `compute_type'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/activerecord-3.1.3/lib/active_r
ecord/reflection.rb:173:in `klass'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/activerecord-3.1.3/lib/active_r
ecord/associations/collection_association.rb:146:in `transaction'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/activerecord-3.1.3/lib/active_r
ecord/associations/collection_association.rb:124:in `concat'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/activerecord-3.1.3/lib/active_r
ecord/associations/collection_proxy.rb:118:in `<<'
from (irb):6
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-3.1.3/lib/rails/comman
ds/console.rb:45:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-3.1.3/lib/rails/comman
ds/console.rb:8:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-3.1.3/lib/rails/comman
ds.rb:40:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
irb(main):007:0>
Here is my users.rb file:
class Users < ActiveRecord::Base
has_and_belongs_to_many :skills
end
Here is my skills.rb file:
class Skills < ActiveRecord::Base
has_and_belongs_to_many :users
end
And here is my schema.rb file:
ActiveRecord::Schema.define(:version => 20111214152402) do
create_table "skills", :force => true do |t|
t.integer "user_id"
t.string "description", :null => false
t.string "skill_name", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "skills", ["user_id"], :name => "index_skills_on_user_id"
create_table "users", :force => true do |t|
t.integer "skill_id"
t.string "first_name", :limit => 25
t.string "last_name", :limit => 50
t.string "email", :default => ""
t.string "password", :limit => 40
t.string "location", :limit => 100
t.string "status"
t.text "bio"
t.string "question1"
t.string "question2"
t.string "availability"
t.string "image"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["skill_id"], :name => "index_users_on_skill_id"
create_table "users_skills", :id => false, :force => true do |t|
t.integer "user_id"
t.integer "page_id"
end
add_index "users_skills", ["user_id", "page_id"], :name => "index_users_skills_on_user_id_and_page_id"
end
If you can help that'd be awesome! If you need to see other files let me know.
user.skills is an array so in order to add a skill, you need to do
user.skills << skill
Additionally, on your schema, I notice that your user_skils table contains wrong foreign key id. I believe they should be user_id and skill_id.
Update
Your users table also looks wrong. You do not need a skill_id in your users table. Similarly, you do not need user_id in your skills table.
This is a small diagram of how the tables and attributes should look like
users skills_users skills
id ----> user_id
skill_id ---> id
Update 2
Your model name looks wrong. It is a convention in RoR to use singular model name. Users should be User. Similarly, for skills.
I think, the problem is that the skill is an instance of Skill, while user.skills expects a collection.
users.skills = [skill] should work, but there are different ways of creating associations.
upd. Dave Newton is right. To add records to an association you should use <<