I have three models in context of this question:
class ClearanceBatch < ActiveRecord::Base
has_many :items
belongs_to :user
end
class Item < ActiveRecord::Base
belongs_to :style
belongs_to :user
belongs_to :clearance_batch
validates :id, :uniqueness => true
end
class User < ActiveRecord::Base
has_many :items, dependent: :destroy
has_many :clearance_batches, dependent: :destroy
enum role: {staff: 0, vendor: 1, admin: 2}
end
Schema:
create_table "clearance_batches", force: :cascade do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "status", default: false
t.string "boughtby", default: ""
t.integer "user_id"
end
add_index "clearance_batches", ["user_id"], name: "index_clearance_batches_on_user_id"
create_table "items", force: :cascade do |t|
t.string "size"
t.string "color"
t.string "status"
t.decimal "price_sold"
t.datetime "sold_at"
t.integer "style_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "clearance_batch_id"
t.integer "user_id"
end
create_table "users", force: :cascade do |t|
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
t.integer "role", default: 0
end
I want to find all items in a batch of the currently logged in user(mainly vendor) with the status "clearanced", and get their details in a loop from controller to my view
Can anyone please help me out with the active record query? Please! :)
The SQLite Query I think would be:
Select I.id from clearance_batches C INNER JOINS Items I on C.id = I.clearance_batch_id where C.user_id = "1" and I.status = "clearanced"
(If 1 is the current user, keeping in mind I am only allowing user of role vendors to be a user in clearance_batch table)
(1) Query:
Items.where(status: "clearanced")
.joins(:clearance_batches)
.where(clearance_batches: {user_id: current_user})
(2) Controller:
#clearanced_items = query(1)
(3) View:
<% #clearanced_items.each do |c_item| %>
...
<% end %>
Related
I have a has_many :through association.
#app/user.rb
class User < ApplicationRecord
has_many :members
has_many :projects, :through => :members
end
#app/project.rb
class Project < ApplicationRecord
has_many :members
has_many :users, :through => :members
end
#app/member.rb
class Member < ApplicationRecord
belongs_to :user
belongs_to :project
end
I have the database schema as follows:
create_table "members", force: :cascade do |t|
t.integer "user_id"
t.integer "project_id"
t.integer "is_owner"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["project_id"], name: "index_members_on_project_id"
t.index ["user_id"], name: "index_members_on_user_id"
end
create_table "projects", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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
I can get Member ID, User_ID, Project_ID, and is_owner when I use the command #project.members
I can get user_id, first_name, last_name, email, and password when I use the command #project.users
What command should I use to get member_id, first_name, last_name?
I can get what I want using the SQL query SELECT * FROM members INNER JOIN users ON users.id = members.user_id but I don't want to use raw SQL.
Can someone tell me how to convert that query into a Ruby on rails command?
You can get your desired result using following code
Member.joins(:user)
It will generate the same query what you are specifying in your question i.e.
SELECT * FROM members INNER JOIN users ON users.id = members.user_id
Users and Sessions are joined by a has_and_belongs_to_many association.
How do I get the unique list of Users that meet the following conditions?
user.coach == true
user.available == true
And then NOT include a user if that user is a coach in any active Session:
session.coach_id == user.id
session.call_ends_at == nil
Is there a way I can write this with ActiveRecord Query language? Do I need to write a pure SQL statement? Some kind of hybrid? What would YOU do?
I also have scopes defined that could be helpful here. But I'm not sure how to add them in:
User.available_coaches (scope)
Session.in_progress (scope)
User model
class User < ActiveRecord::Base
has_many :client_sessions, class_name: 'Session', foreign_key: :client_id
has_many :coach_sessions, class_name: 'Session', foreign_key: :coach_id
scope :coaches, -> { where(coach: true) }
scope :available_coaches, -> { coaches.where(available: true) }
Session model
class Session < ActiveRecord::Base
belongs_to :client, class_name: 'User'
belongs_to :coach, class_name: 'User'
scope :in_progress, -> { where.not(coach: nil).where(call_ends_at: nil) }
Schema
create_table "sessions", force: :cascade do |t|
t.integer "client_id"
t.integer "coach_id"
t.boolean "canceled", default: false
t.datetime "coach_accepted_at"
t.datetime "call_begins_at"
t.datetime "call_ends_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "sessions", ["client_id"], name: "index_sessions_on_client_id", using: :btree
add_index "sessions", ["coach_id"], name: "index_sessions_on_coach_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.boolean "coach", default: false
t.boolean "available", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I would do it with SQL exists:
User.where(coach: true, available: true).
where("not exists (select 1 from sessions " +
"where sessions.coach_id = users.id and sessions.call_ends_at is null)")
Note that since there is no join to sessions there is no need for .uniq.
im trying to make a search form in a table that contains two ids as values, one of them is the id of an user and the other is the id of a project.
Here is my database schema:
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.text "bio"
t.float "lastLatitude"
t.float "lastLongitude"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "swipes"
t.string "profile_image"
end
create_table "projects", force: :cascade do |t|
t.string "name"
t.text "bio"
t.integer "user_id"
t.string "salary"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "likes"
t.string "image"
t.float "latitude"
t.float "longitude"
end
create_table "matches", force: :cascade do |t|
t.integer "user_id"
t.integer "project_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
What i want to do is to create a search form in the matches index view to filter the matches by the user name or the project name, but i don't know how to do it, this is what i have right now:
def self.search(search)
if search
where('User(user_id).name LIKE :search OR Project.name LIKE :search', search: "%#{search}%")
else
where(nil)
end
end
Is it possible to do that?
Any help is welcome
I suggest a scope approach
class Match < ActiveRecord::Base
belongs_to :project
belongs_to :user
scope name, ->(n) {
joins(:user, :project).where("users.name like ? or projects.name like ? ", "%#{n}%", "%#{n}%")
}
end
class User < ActiveRecord::Base
has_many :projects
scope :name, ->(n) {
where("users.name like ?", "%n%")
}
end
class Project < ActiveRecord::Base
scope :name, ->(n) {
where("projects.name like ?", "%n%")
}
end
when I run the rails server, localhost displays this error:
ActiveRecord::PendingMigrationError (Migrations are pending.
To resolve this issue, run: bin/rake db:migrate RAILS_ENV=development):
I have run the bin/rake... and the next error says:
$ bundle exec bin/rake db:migrate RAILS_ENV=development
== 20150225172130 CreateVotes:
migrating ======================================
-- create_table(:votes)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table "votes" already exists: CREATE TABLE "votes"
("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "value" varchar(255),
"user_id" integer, "post_id" integer, "created_at" datetime, "updated_at"
datetime)
_create_votes.rb
class CreateVotes < ActiveRecord::Migration
def change
create_table :votes do |t|
t.string :value
t.references :user, index: true
t.references :post, index: true
t.timestamps
end
end
end
Basically, it tells me I have migrations pending, but when I attempt to migrate it says the table already exists.
20150225172130 CreateVotes:
migrating ======================================
-- create_table(:votes)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table "votes" already exists: CREATE TABLE "votes"...
after running db:drop:all
db:create
db:migrate
db:test:clone
votes are now showing up in schema.rb:
ActiveRecord::Schema.define(version: 20150101200224) do
create_table "comments", force: true do |t|
t.text "body"
t.integer "post_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
create_table "posts", force: true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.string "name"
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.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.datetime "created_at"
t.datetime "updated_at"
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
create_table "votes", force: true do |t|
t.integer "value"
t.integer "user_id"
t.integer "post_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "votes", ["post_id"], name: "index_votes_on_post_id"
add_index "votes", ["user_id"], name: "index_votes_on_user_id"
end
model/vote.rb
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
You could do this:
class CreateVotes < ActiveRecord::Migration
def change
unless table_exists? :votes
create_table :votes do |t|
t.string :value
t.references :user, index: true
t.references :post, index: true
t.timestamps
end
end
end
I've run into this before when a migration didn't run as expected. But you should also check your schema.rb file to make sure that the votes table has the columns that the migration adds.
I've been having a problem with an ActiveRecord query in Rails 4:
my models:
class Addressee < ActiveRecord::Base
has_and_belongs_to_many :emails
end
class Email < ActiveRecord::Base
belongs_to :author, foreign_key: :from_id, class_name: "Addressee"
has_and_belongs_to_many :addressees
end
my schema.rb
create_table "addressees", force: true do |t|
t.string "token", limit: nil
t.string "domain", limit: nil
t.string "email", limit: nil
t.string "name", limit: nil
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "addressees_emails", force: true do |t|
t.integer "addressee_id"
t.integer "email_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "emails", force: true do |t|
t.string "message_id", limit: nil
t.integer "from_id"
t.string "subject", limit: nil
t.text "body"
t.datetime "date"
t.datetime "created_at"
t.datetime "updated_at"
end
my query:
# Returns correct emails
query_params = { "addressees.email" => "test#example.com" }
#emails = Email.includes(:addressees).where(query_params).references(:addressees)
my problem:
# Returns only the addressee matching the email from query params
#emails.last.addressees
#<ActiveRecord::Associations::CollectionProxy [#<Addressee id: 12, token: "test", domain: "example.com", email: "test#example.com", name: nil, created_at: "2014-09-25 14:06:34", updated_at: "2014-09-25 14:06:34">]>
#Returns the wrong count
#emails.last.addressees.size
#=> 1
#Returns the correct count (because it does a new query)
#emails.last.addressees.count
#=> 3
my question:
How can I modify the query to include all addressees without the need to do another query?. I'm passing the #emails var to my json serializer and now it only includes 1 addressee instead of all 3.
#emails = Email.where('emails.id IN SELECT(email_id FROM addressees_emails WHERE addressee_id IN (SELECT id FROM addressees WHERE email IN (?)))', %w[test#example.com test2#example.com]).includes(:addressees)