Rails c sql command is rollingback instead of updating - sql

so I tried to run rails c of this:
Borrower.update(1, :raised=> 0)
and this:
Borrower.update(1, raised: 0)
and I get a roll back with this:
Borrower Load (0.3ms) SELECT "borrowers".* FROM "borrowers" WHERE "borrowers"."id" = $1 LIMIT 1 [["id", 1]]
(0.2ms) BEGIN
Borrower Exists (0.5ms) SELECT 1 AS one FROM "borrowers" WHERE (LOWER("borrowers"."email") = LOWER('j#kay.com') AND "borrowers"."id" != 1) LIMIT 1
(0.2ms) ROLLBACK
"table with raised = 0"
1 row in set
This is my model for "Borrower":
class Borrower < ActiveRecord::Base
has_many :lenders
has_many :histories, dependent: :destroy
has_many :borrowed_from, through: :histories, source: :lender
EMAIL_REGEX = /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]+)\z/i
validates :first_name, :last_name, :email, :purpose, :description, :money, presence: true
validates :email, uniqueness: {case_sensitive: false}, format: {with: EMAIL_REGEX}
has_secure_password
end
and my Schema:
create_table "borrowers", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "password_digest"
t.integer "money"
t.string "purpose"
t.text "description"
t.integer "raised"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
How do I permanently update the "raised"?

It's likely the validation fails, try to print the validation errors on your console:
borrower = Borrower.update(1, raised: 0)
puts borrower.errors
Another solution if you want to explicitly skip the validation might be update_attribute:
Borrower.find(1).update_attribute(:raised, 0)
If you additionally want to skip the callbacks and avoid touching updated_at there's also update_column:
Borrower.find(1).update_column(:raised, 0)
If raised is sort of a boolean attribute you could also go for toggle!:
Borrower.find(1).toggle!(:raised)

Related

#<ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: users.sender_id:

I'm building three models in my rails application. One model references the same model twice as shown in my DB Schema. The only problem is that when I make a POST Request to create a new record in my shipment table. I get this error:
#<ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: users.sender_id: SELECT \"users\".* FROM \"users\" WHERE \"users\".\"sender_id\" = ? LIMIT ?>
I don't think that I need to add a sender_id & receiver_id column in my users table because the sender_id & receiver_id are basically the User_ID in the users column. Any help would be much appreciated it!
This is my user.rb file:
class User < ApplicationRecord
has_many :shipments
end
This is my shipment.rb
class Shipment < ApplicationRecord
belongs_to :sender, class_name: "User", primary_key: "sender_id"
belongs_to :receiver, class_name: "User", primary_key: "receiver_id"
validates_uniqueness_of :tntcode
end
This is my shipments_controller:
class ShipmentsController < ApplicationController
def index
shipments = Shipment.all
end
def show
shipment = Shipment.find(params[:id])
end
def create
shipment = Shipment.new(shipment_params)
if shipment.save
render json: {status: 'Shipment created successfully'}, status: :created
else
render json: { errors: shipment.errors.full_messages }, status: :bad_request
end
end
def shipment_params
params.require(:shipment).permit(:tntcode, :status, :shipment_type, :weight, :content, :price, :sender_id, :receiver_id)
end
end
And my schema.rb:
ActiveRecord::Schema.define(version: 20180826123320) do
create_table "shipments", force: :cascade do |t|
t.integer "tntcode"
t.string "status"
t.string "shipment_type"
t.integer "weight"
t.string "content"
t.integer "price"
t.integer "sender_id"
t.integer "receiver_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["receiver_id"], name: "index_shipments_on_receiver_id"
t.index ["sender_id"], name: "index_shipments_on_sender_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email", null: false
t.string "role"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "photourl"
t.string "userid"
end
end
You don't want to change the primary_key on your belongs_to associations: that's the other table's ID column (id).
You instead want:
belongs_to :sender, class_name: "User", foreign_key: "sender_id"
belongs_to :receiver, class_name: "User", foreign_key: "receiver_id"
... which is the default, so this should work too:
belongs_to :sender, class_name: "User"
belongs_to :receiver, class_name: "User"

Association command using has_many :through associations in Ruby on Rails

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

How do I write an ActiveRecord query that filters out results from a joined table?

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.

Moving data to another table

I have a question associated with moving data from one table to another. I am using Postgres as a database.
I have two models:
class User < ActiveRecord::Base
has_many :emails
end
class Email < ActiveRecord::Base
belongs_to :user
end
schema looks like this:
create_table "users", force: :cascade do |t|
t.string "first_name", limit: 255
t.string "last_name", limit: 255
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "emails", force: :cascade do |t|
t.string "email", null: false
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Now I want to move the latest email for the user and save it in users table email column. I can easily do it using Rails models in migration but then when I rename model or remove it. Migration will fail. Is there any easy way to do it with raw sql?
You can use window functions. The example below is a starting point.
UPDATE users u
SET u.email = (SELECT
MAX(FIRST_VALUE(email)) OVER (PARTITION BY user_id ORDER BY created_at DESC)
FROM emails e
WHERE e.user_id = u.id);
You can still use ActiveRecord with fake classes just for the purpose of migration. Something like:
class YourMigration < ActiveRecord::Migration
class FakeUser < ActiveRecord::Base
self.table_name = 'users'
has_many :fake_emails, foreign_key: 'user_id'
end
class FakeEmail < ActiveRecord::Base
self.table_name = 'emails'
belongs_to :fake_user, foreign_key: 'user_id'
end
def change
FakeUser.all.each do |user|
[...]
end
end
end

rails no such column error

I have the following app. A Movie has many reviews, a moviegoer has many reviews.
When I try to associate a review with a movie I get the following error
Review Load (0.1ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."movie_id" = 5
SQLite3::SQLException: no such column: reviews.movie_id: SELECT "reviews".* FROM "reviews" WHERE "reviews"."movie_id" = 5
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: reviews.movie_id: SELECT "reviews".* FROM "reviews" WHERE "reviews"."movie_id" = 5
after using a sql gui editor I found that the correct query should be
SELECT "reviews".* FROM "reviews" WHERE "movie_id" = 5
review.rb
class Review < ActiveRecord::Base
belongs_to :movie
belongs_to :moviegoer
attr_protected :moviegoer_id
end
movie.rb and moviegoer.rb have
has_many :reviews
in them.
schema.rb
ActiveRecord::Schema.define(:version => 20130222225620) do
create_table "moviegoers", :force => true do |t|
t.string "name"
t.string "provider"
t.string "uid"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "movies", :force => true do |t|
t.string "title"
t.string "rating"
t.text "description"
t.datetime "release_date"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "reviews", :force => true do |t|
t.integer "potatoes"
t.text "comments"
t.integer "moviegoers_id"
t.integer "movies_id"
end
end
What am I doing wrong? why is rails querying "reviews"."movie_id" instead of just "movie_id"?
You have the wrong column name in your migration. The rails convention is that foreign keys are to be singular. If they are not then you need to tell rails what the foreign key is with an options hash on the association.
Either rollback your migration, fix the column name (moviegoers_id is wrong as well) then migrate again, or tell rails the foreign key.
Class Review < ActiveRecord::Base
belongs_to :movie, :foreign_key => 'movies_id'
belongs_to :moviegoer, :foreign_key => 'moviegoers_id'
end
And the same has to happen on the has many side of both models.