I changed my User model to accept_nested_attributes_for Profile, and I'm trying to create the User and Profile at the same time. I'm using Devise for authentication.
This seems to be working -- except for one giant gotcha...
Every time I create a new user it crashes the app with "Illegal Instruction", and when I check the log it looks like this...
Started POST "/users" for 127.0.0.1 at 2011-04-18 21:01:54 -0500
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"‚úì", "authenticity_token"=>"Rua6PUxnE4a4TvaFcVMfmycw8Y9AFRjEsXVrqwWC2EM=", "user"=>{"email"=>"_______________________#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "profile_attributes"=>{"first_name"=>"Name", "last_name"=>"Tester"}, "student_claimed"=>"false", "school"=>"", "invite_code"=>"Texas!", "terms_of_service"=>"1"}, "commit"=>"Create Account!"}
[1m[35mSQL (0.3ms)[0m SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
[1m[36mSQL (0.3ms)[0m [1m SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
[0m
[1m[35mUser Load (0.2ms)[0m SELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('_______________________#gmail.com')) LIMIT 1
[1m[36mInvitation Load (0.1ms)[0m [1mSELECT "invitations".* FROM "invitations" WHERE "invitations"."code" = 'Texas!' LIMIT 1[0m
[1m[35mUser Load (0.1ms)[0m SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = 'duALIT6yCL5ShpMvbw79' LIMIT 1
[1m[36mRole Load (0.3ms)[0m [1mSELECT "roles".* FROM "roles" WHERE "roles"."name" = 'member' LIMIT 1[0m
[1m[35mAREL (0.3ms)[0m UPDATE "invitations" SET "remaining_uses" = 9993, "updated_at" = '2011-04-19 02:01:54.506243' WHERE "invitations"."id" = 1
[1m[36mAREL (0.2ms)[0m [1mINSERT INTO "users" ("email", "encrypted_password", "reset_password_token", "remember_token", "remember_created_at", "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "created_at", "updated_at", "plan_code", "confirmation_token", "confirmed_at", "confirmation_sent_at", "student_claimed", "student_confirmed", "school", "invitation_id") VALUES ('_______________________#gmail.com', '$2a$10$7qzC7T6b1kLiXvPSkMRkduCFClBznDWnnOu7I1ssU8blB9NMJznn2', NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, '2011-04-19 02:01:54.509656', '2011-04-19 02:01:54.509656', NULL, 'duALIT6yCL5ShpMvbw79', NULL, '2011-04-19 02:01:54.437796', 'f', 'f', '', 1)[0m
[1m[35mSQL (0.1ms)[0m INSERT INTO "roles_users" ("role_id", "user_id") VALUES (3, 6)
Rendered devise/mailer/confirmation_instructions.html.erb (0.9ms)
Sent mail to _________#gmail.com (1966ms)
Date: Mon, 18 Apr 2011 21:01:55 -0500
From: __________
Reply-To: ___________
To: _____________
Message-ID: <4daced1352c84_1ff5817d6b04978cd#Titan.local.mail>
Subject: Please confirm your email address
Mime-Version: 1.0
Content-Type: text/html;
charset=UTF-8
Content-Transfer-Encoding: 7bit
<p>Name,</p>
<p>You registered with the email address: _________#gmail.com. You can confirm your account through the link below:</p>
<p>Confirm my account</p>
<p>Thanks for signing up!</p>
[1m[36mAREL (0.2ms)[0m [1mINSERT INTO "profiles" ("first_name", "last_name", "created_at", "updated_at", "user_id", "avatar_file_name", "avatar_content_type", "avatar_file_size", "avatar_updated_at", "address1", "city", "state", "country", "zip") VALUES ('Name', 'Tester', '2011-04-19 02:01:57.266502', '2011-04-19 02:01:57.266502', 6, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)[0m
[paperclip] Saving attachments.
[1m[35mUser Load (0.1ms)[0m SELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('_______________________#gmail.com')) AND ("users".id <> 6) LIMIT 1
[1m[36mUser Load (1.6ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1[0m
[1m[35mProfile Load (1.6ms)[0m SELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)
[1m[36mCACHE (0.0ms)[0m [1mSELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('_______________________#gmail.com')) AND ("users".id <> 6) LIMIT 1[0m
[1m[35mCACHE (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1
[1m[36mCACHE (0.0ms)[0m [1mSELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)[0m
[1m[35mCACHE (0.0ms)[0m SELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('_______________________#gmail.com')) AND ("users".id <> 6) LIMIT 1
[1m[36mCACHE (0.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1[0m
[1m[35mCACHE (0.0ms)[0m SELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)
[1m[36mCACHE (0.0ms)[0m [1mSELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('_______________________#gmail.com')) AND ("users".id <> 6) LIMIT 1[0m
[1m[35mCACHE (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1
[1m[36mCACHE (0.0ms)[0m [1mSELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)[0m
[1m[35mCACHE (0.0ms)[0m SELECT "users"."id" FROM "users" WHERE (LOWER("users"."email") = LOWER('_______________________#gmail.com')) AND ("users".id <> 6) LIMIT 1
[1m[36mCACHE (0.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1[0m
[1m[35mCACHE (0.0ms)[0m SELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)
... and so on for about 100 more lines ...
[1m[35mCACHE (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 6 LIMIT 1
[1m[36mCACHE (0.0ms)[0m [1mSELECT "profiles".* FROM "profiles" WHERE ("profiles".user_id = 6)[0m
[1m[36mSQL (0.3ms)[0m [1m SELECT name
So, this wasn't happening before I started accepting nested attributes... and I'm pretty confused as to why it's happening now. Does anyone have any insight into how to debug this and fix the problem?
Thanks!
--EDIT--
User Model:
class User < ActiveRecord::Base
# RELATIONSHIPS
has_one :profile, :dependent => :destroy
has_many :photos
has_many :votes
has_many :voted_photos, :through => :votes, :source => :photo
has_many :ratings
has_many :rated_photos, :through => :ratings, :source => :photo
has_many :comments
has_and_belongs_to_many :roles
has_many :assignments
has_many :collections, :through => :assignments
belongs_to :invitation
accepts_nested_attributes_for :profile
# VIRTUAL ATTRIBUTES
attr_accessor :invite_code
# AUTHENTICATION
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
# SECURITY
attr_accessible :email, :password, :password_confirmation, :remember_me, :confirmed_at, :invite_code, :student_claimed, :school, :terms_of_service, :profile_attributes
# FILTERS
before_create :set_role_to_member, :set_invitation
after_save :update_recurly_account, :unless => Proc.new { Rails.env.test? }
# VALIDATIONS
validates_acceptance_of :terms_of_service, :message => "You must agree to the terms of service in order to create an account."
validate :invitation_status, :on => :create
validates_presence_of :profile
validates_associated :profile
# DELEGATES
delegate :first_name, :last_name, :full_name,
:to => :profile,
:allow_nil => true
# ROLES
def set_role_to_member
self.roles << Role.find_by_name('member')
end
def has_role?( r )
!roles.find_by_name( r ).nil?
end
def list_roles
list = []
roles.all.each do |r|
list << r.name
end
list.join(', ')
end
# DEVISE RELATED
# Hook up recurly account after confirmation
def confirm!
self.setup_recurly_account unless Rails.env.test?
if student_claimed && validate_student_email
self.student_confirmed = true
self.save
end
super
end
protected
# Don't require password on update
def password_required?
!persisted? || password.present? || password_confirmation.present?
end
public
# RECURLY RELATED
def setup_recurly_account
...
end
private
def update_recurly_account
...
end
def validate_student_email
self.email =~ /\.edu$/ ? true : false
end
def invitation_status
...
end
def set_invitation
...
end
end
Profile Model
class Profile < ActiveRecord::Base
include Helpers::AssetStorage
# RELATIONSHIPS
belongs_to :user
stores_file_as :avatar,
:styles => { :tenth => "87x87#", :eighth => "106x106#" },
:filename_interpolation => "avatars/:user_id/:id_:style.:extension",
:default_url => '/images/no_avatar_:style.png'
# VALIDATIONS
validates_presence_of :first_name, :last_name
# CALLBACKS
after_update :save_user
def full_name
[first_name,last_name].join(" ")
end
private
def save_user
self.user.save!
end
end
You don't need the save_user callback for Profile model.
When doing user.save, it automatically save user.profile. Due to the callback, the user.profile saved, and it calls it's user to save again. And the user save, it also save his profile......
That's the loop.
So the simplest modification would be remove the after_update callback in Profile model.
If you want to save the profile only, use profile.save. If the user object has updates too, use user.save or profile.user.save.
Related
I am using rails 5.0.0
I want to make a query that will let me display all the posts the current user has made. The two relevant tables I have are:
create_table "discussions", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "channel_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
....
t.string "unconfirmed_email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "username"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["username"], name: "index_users_on_username", unique: true
end
create_table "replies", force: :cascade do |t|
t.text "reply"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "discussion_id"
t.integer "user_id"
end
and the relationships are as follows:
class Discussion < ApplicationRecord
belongs_to :channel
belongs_to :user
has_many :replies, dependent: :destroy
has_many :users, through: :replies
class Reply < ApplicationRecord
belongs_to :discussion
belongs_to :user
class User < ApplicationRecord
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable
has_many :notifications, foreign_key: :recipient_id
has_many :discussions, dependent: :destroy
has_many :channels, through: :discussions
in my discussions_controller.rb file i have the following line
#discussions = Discussion.includes(:users).where('users.id' => current_user).order('discussions.created_at desc')
and in my view file I have
<% #discussions.each do |discussion| %>
...
<% end %>
I expect there to be a few entries since I have created them, however no entries are displayed at all. This is what is printed in the terminal window
Processing by DiscussionsController#index as HTML
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendering discussions/index.html.erb within layouts/application
SQL (0.5ms) SELECT "discussions"."id" AS t0_r0, "discussions"."title" AS t0_r1, "discussions"."content" AS t0_r2, "discussions"."created_at" AS t0_r3, "discussions"."updated_at" AS t0_r4, "discussions"."user_id" AS t0_r5, "discussions"."channel_id" AS t0_r6, "users"."id" AS t1_r0, "users"."email" AS t1_r1, "users"."encrypted_password" AS t1_r2, "users"."reset_password_token" AS t1_r3, "users"."reset_password_sent_at" AS t1_r4, "users"."remember_created_at" AS t1_r5, "users"."sign_in_count" AS t1_r6, "users"."current_sign_in_at" AS t1_r7, "users"."last_sign_in_at" AS t1_r8, "users"."current_sign_in_ip" AS t1_r9, "users"."last_sign_in_ip" AS t1_r10, "users"."confirmation_token" AS t1_r11, "users"."confirmed_at" AS t1_r12, "users"."confirmation_sent_at" AS t1_r13, "users"."unconfirmed_email" AS t1_r14, "users"."created_at" AS t1_r15, "users"."updated_at" AS t1_r16, "users"."username" AS t1_r17 FROM "discussions" LEFT OUTER JOIN "replies" ON "replies"."discussion_id" = "discussions"."id" LEFT OUTER JOIN "users" ON "users"."id" = "replies"."user_id" WHERE "users"."id" = 1 ORDER BY discussions.created_at desc
Rendered shared/_discussions.html.erb (8.5ms)
Channel Load (0.3ms) SELECT "channels".* FROM "channels" ORDER BY created_at desc
Role Load (0.3ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = ? AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1]]
Rendered discussions/_sidebar.html.erb (34.1ms)
Rendered discussions/index.html.erb within layouts/application (46.1ms)
Completed 200 OK in 245ms (Views: 165.7ms | ActiveRecord: 6.7ms)
If I use
#discussions = Discussion.includes(:users).order('discussions.created_at desc')
Then all the discussion posts display as they normally would as if the .includes statement was not there.
So, how can I change my query to list out the discussions made by the current user?
Update As per Shiko's comment, here is the output given with his input in the rails console
2.3.0 :001 > User.find(1).discussions
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Discussion Load (0.5ms) SELECT "discussions".* FROM "discussions" WHERE "discussions"."user_id" = ? [["user_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Discussion id: 1, title: "Test", content: "alkjdflk slkfj ", created_at: "2018-04-08 22:40:06", updated_at: "2018-04-08 22:40:06", user_id: 1, channel_id: nil>, #<Discussion id: 2, title: "Fake Bakesale", content: "Come buy cookies", created_at: "2018-04-08 23:29:17", updated_at: "2018-04-08 23:29:17", user_id: 1, channel_id: 1>, #<Discussion id: 3, title: "Fake Bakesale", content: "Come buy cookies", created_at: "2018-04-08 23:30:18", updated_at: "2018-04-08 23:30:18", user_id: 1, channel_id: 1>, #<Discussion id: 4, title: "Meeting today", content: "Come to the meeting", created_at: "2018-04-08 23:35:59", updated_at: "2018-04-08 23:35:59", user_id: 1, channel_id: 1>, #<Discussion id: 5, title: "New post", content: "asdf ", created_at: "2018-04-15 21:50:20", updated_at: "2018-04-15 21:50:20", user_id: 1, channel_id: 2>]>
2.3.0 :002 >
First thing, if you run below command in rails console, you should get an below expected error :
#discussions = Discussion.includes(:users).where('users.id' => current_user).order('discussions.created_at desc')
Expected error:
ActiveRecord::ConfigurationError: Can't join 'Discussion' to
association named 'users'; perhaps you misspelled it?
To fix this issue, you have to use :user instead of :users as below, simply because each discussion belongs to one user and not many :
#discussions = Discussion.includes(:user).where('users.id' => current_user).order('discussions.created_at desc')
There is a more a clean one way to get the current user discussions, using below:
Controller:
#user = User.find(curren_user_id)
ERB file:
<% #user.discussions.each do |discussion| %>
.....
<% end %>
You can do this:
#discussions = Discussion.includes(:user).
where(users: { id: current_user.id }).
order("discussions.created_at desc")
If you don't need to reference the user attributes in your view, you can also do this, which avoids the join altogether:
#discussions = Discussion.
where(user_id: current_user.id).order(created_at: :desc)
This is what I've tried, and I'm not sure where the problem is. . .
My model:
class User < ActiveRecord::Base
acts_as_authentic
has_many :assignments
end
Migration:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :login, :null => false
t.string :crypted_password, :null => false
t.string :password_salt, :null => false
t.string :persistence_token, :null => false
t.timestamps null: false
end
end
end
This is what I'm getting in Rails console when trying to create a user:
`<main>'2.2.0 :004 > User.create(login:'whatever', password:'1', password_confirmation:'1')
(0.1ms) begin transaction
User Exists (1.1ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."login") = LOWER('whatever') LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE "users"."persistence_token" = '4886c517de2414c730b7ed5cc296b0e19c3e56ee398fb0aeed0531c55cbb04fd2a8ce577a4d5bd7dbb52e46cf9ab5e27e287af0993a708d07ded12553460d11c' LIMIT 1
(0.1ms) rollback transaction
=> #<User id: nil, login: "whatever", crypted_password: "400$8$45$c054050d7ce04047$335b3dec54f141e7ab030e1f...", password_salt: "CQlMGatvdGngFXiogDcW", persistence_token: "4886c517de2414c730b7ed5cc296b0e19c3e56ee398fb0aeed...", created_at: nil, updated_at: nil>
No users are created after it:
2.2.0 :005 > User.all
User Load (61.5ms) SELECT "users".* FROM "users"
=> #<ActiveRecord::Relation []>
No errors and some weird SQL. What could be the problem?
EDIT: Just tried u = User.create(login:'whatever', password:'123', password_confirmation:'123'); u.errors.to_json
And I got:
=> "{\"password\":[\"is too short (minimum is 4 characters)\"],\"password_confirmation\":[\"is too short (minimum is 4 characters)\"]}"
So that was my problem, password was too short. Too bad Rails didn't print it by default when I was seeding db. Thanks all!
When creating a join table as follows
class Project < ActiveRecord::Base
belongs_to :user
has_many :time_pledges, dependent: :destroy
has_many :volunteers, through: :time_pledges
class User < ActiveRecord::Base
has_many :projects, dependent: :destroy
has_many :time_pledges, foreign_key: "volunteer_id", dependent: :destroy
has_many :volunteering, through: :time_pledges, source: :project
class TimePledge < ActiveRecord::Base
belongs_to :volunteer, class_name: "User"
belongs_to :project
I am able to do the following #project.volunteers.count and get an answer for how many users are volunteering for a specific project at that time. However when I update the project model to be able to access the hours_pledged attribute of the join table model (time_pledges) as follows:
has_many :volunteers, -> { select('users.*, time_pledges.hours_pledged as hours_pledged')}, through: :time_pledges
I am no longer able to access #project.volunteers.count. The error I get is as follows
P1.volunteers
User Load (1.6ms) SELECT users.*, time_pledges.hours_pledged as hours_pledged FROM "users" INNER JOIN "time_pledges" ON "users"."id" = "time_pledges"."volunteer_id" WHERE "time_pledges"."project_id" = $1 [["project_id", 300]]
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 1, email: "durham#example.com", encrypted_password: "$2a$10$4fyCd4GGtwZ0NRzrJuPDd.KWAhXWWumJ1LqtqZOSYWQ...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2015-03-06 08:59:06", updated_at: "2015-03-06 08:59:06">]>
>> P1.volunteers.count
PG::SyntaxError: ERROR: syntax error at or near "as"
LINE 1: SELECT COUNT(users.*, time_pledges.hours_pledged as hours_pl...
^
: SELECT COUNT(users.*, time_pledges.hours_pledged as hours_pledged) FROM "users" INNER JOIN "time_pledges" ON "users"."id" = "time_pledges"."volunteer_id" WHERE "time_pledges"."project_id" = $1
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "as"
LINE 1: SELECT COUNT(users.*, time_pledges.hours_pledged as hours_pl...
^
: SELECT COUNT(users.*, time_pledges.hours_pledged as hours_pledged) FROM "users" INNER JOIN "time_pledges" ON "users"."id" = "time_pledges"."volunteer_id" WHERE "time_pledges"."project_id" = $1
Also after I try to do a #project.volunteers.count I am no longer able to access any of my Users again (until I restart a console session). For example if I do something like U5=User.find_by(id:5) after a #project.volunteers.count I get the following message:
User Load (1.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 5]]
PG::InFailedSqlTransaction: ERROR: current transaction is aborted, commands ignored until end of transaction block
: SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1
ActiveRecord::StatementInvalid: PG::InFailedSqlTransaction: ERROR: current transaction is aborted, commands ignored until end of transaction block
: SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1
Any help is appreciated
Thanks
D
EDIT 1
Schema
create_table "time_pledges", force: :cascade do |t|
t.integer "volunteer_id"
t.integer "project_id"
t.integer "hours_pledged"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "time_pledges", ["project_id"], name: "index_time_pledges_on_project_id", using: :btree
add_index "time_pledges", ["volunteer_id", "project_id"], name: "index_time_pledges_on_volunteer_id_and_project_id", unique: true, using: :btree
add_index "time_pledges", ["volunteer_id"], name: "index_time_pledges_on_volunteer_id", using: :btree
Using times_pledges instead of time_pledges
>> P1=Project.first Project Load (1.7ms) SELECT "projects".* FROM "projects" ORDER BY "projects"."created_at" DESC LIMIT 1 => #<Project id: 301, title: "awe", user_id: 101, created_at: "2015-03-06 15:19:17", updated_at: "2015-03-06 15:19:17", required_hours: 7> >> P1.volunteers NameError: uninitialized constant Project::TimesPledge
Using
has_many :volunteers, -> { select('users.*, time_pledges.hours_pledged hours_pledged')}, through: :time_pledges
gives
>> P1.volunteers
User Load (1.4ms) SELECT users.*, time_pledges.hours_pledged hours_pledged FROM "users" INNER JOIN "time_pledges" ON "users"."id" = "time_pledges"."volunteer_id" WHERE "time_pledges"."project_id" = $1 [["project_id", 301]]
=> #<ActiveRecord::Associations::CollectionProxy []>
>> P1.volunteers.count
PG::SyntaxError: ERROR: syntax error at or near "hours_pledged"
LINE 1: SELECT COUNT(users.*, time_pledges.hours_pledged hours_pledg...
^
: SELECT COUNT(users.*, time_pledges.hours_pledged hours_pledged) FROM "users" INNER JOIN "time_pledges" ON "users"."id" = "time_pledges"."volunteer_id" WHERE "time_pledges"."project_id" = $1
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "hours_pledged"
LINE 1: SELECT COUNT(users.*, time_pledges.hours_pledged hours_pledg...
^
: SELECT COUNT(users.*, time_pledges.hours_pledged hours_pledged) FROM "users" INNER JOIN "time_pledges" ON "users"."id" = "time_pledges"."volunteer_id" WHERE "time_pledges"."project_id" = $1
In using Postgresql I don't use AS unless it's for a select statement that I am joining to i.e.
SELECT parts.*, alias_skus
FROM parts
LEFT JOIN (
SELECT part_id, array_agg(sku) alias_skus
FROM part_aliases GROUP BY part_id)
AS sub1
ON parts.id = sub1.part_id;
For column aliases, just leave out the 'AS'. You can see here I'm using the alias alias_skus.
thus:
has_many :volunteers, -> { select('users.*, time_pledges.hours_pledged hours_pledged')}, through: :time_pledges
I am trying to set up a messaging system on my app and I had it working, but now ActiveRecord is saving the wrong id for the recipient_id.
Here's where the user.id is loaded as 3 but when the values are inserted the messages's recipient.id is 5:
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id"
ASC LIMIT 1
Message Load (0.4ms) SELECT "messages".* FROM "messages" LIMIT 1
User Load (0.6ms) SELECT "users".* FROM "users" LIMIT 1
(0.5ms) BEGIN
SQL (1.3ms) INSERT INTO "messages" ("content", "created_at", "recepient_id", "sender_id",
"subject", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["content", "erferfe"],
["created_at", Wed, 17 Dec 2014 19:15:08 UTC +00:00], ["recepient_id", 5], ["sender_id", 3],
["subject", "erfer"], ["updated_at", Wed, 17 Dec 2014 19:15:08 UTC +00:00]]
(5.4ms) COMMIT
Redirected to http://0.0.0.0:3000/messages
Completed 302 Found in 23ms (ActiveRecord: 9.6ms)
Here's MessagesController#create:
def create
#message = current_user.sent_messages.new(message_params)
#message.recepient_id = User.find_by(params[:id]).id
if #message.save
flash[:notice] = 'Message has been sent.'
redirect_to messages_path
else
render :action => :new
end
end
Here's messages.rb:
class Message < ActiveRecord::Base
belongs_to :sender, class_name: "User", primary_key: "sender_id"
belongs_to :recepient, class_name: "User", primary_key: "recepient_id"
belongs_to :user
This is the routing for the messages:
resources :users do
resources :messages
end
This is the view:
<div class="ui button"><i class="mail icon"></i><%= link_to 'Message', new_user_message_path(#user) %></div>
Message_params:
def message_params
params.require(:message).permit(:subject, :user_id, :content, :recepient_id)
end
User.rb
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :omniauthable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauth_providers => [:facebook, :twitter]
TEMP_EMAIL_PREFIX = 'change#me'
TEMP_EMAIL_REGEX = /\Achange#me/
attr_accessor :login
has_many :projects, class_name: "Project", foreign_key: "creator_id"
has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
has_many :recieved_messages, class_name: "Message", foreign_key: 'recepient_id'
has_many :messages
has_many :projects, dependent: :destroy
has_many :authentications, :dependent => :destroy
validates :email, presence: true,
uniqueness: true,
format: {
with: /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9\.-]+\.[A-Za-z]+\Z/
}
validates_format_of :email, :without => TEMP_EMAIL_REGEX, on: :update
def downcase_email
self.email = email.downcase
end
def generate_password_reset_token
update_attribute(:password_reset_token, SecureRandom.urlsafe_base64(48))
end
def self.find_for_facebook_oauth(auth)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(:first_name => auth.extra.raw_info.first_name,
:last_name => auth.extra.raw_info.last_name,
:avatar => auth.info.image,
:provider => auth.provider,
:uid => auth.uid,
:email => auth.info.email,
:password => Devise.friendly_token[0,20]
)
user.confirm!
end
user.save
end
def self.find_for_twitter_oauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.avatar = auth.info.image
user.save
end
end
After code change suggested:
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 ORDER BY "users"."id" ASC
LIMIT 1
Message Load (0.3ms) SELECT "messages".* FROM "messages" LIMIT 1
(0.1ms) BEGIN
SQL (0.4ms) INSERT INTO "messages" ("content", "created_at", "sender_id", "subject", "updated_at")
VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["content", "efvefvf"], ["created_at", Wed, 17 Dec 2014
21:02:48 UTC +00:00], ["sender_id", 2], ["subject", "erfvef"], ["updated_at", Wed, 17 Dec 2014
21:02:48 UTC +00:00]]
(7.2ms) COMMIT
Also when I go /users/:user_id/messages my css and javascript files don't work
I am assuming that this feature is initialized from a User "Profile" page which allows the current session user (sender) to send a message to the profile user (recipient).
First off, in your Message model, you do not need belongs_to :user on the Message model nor do you need has_many :messages on the User model.
Next, you have way over complicated the #create action:
def create
#message = current_user.sent_messages.new(message_params)
#message.recipient_id = params[:user_id]
if #message.save
flash[:notice] = 'Message has been sent.'
redirect_to messages_path
else
render :action => :new
end
end
Now, adjust your message_params. You do not need the user_id (will be provided by current_user) nor do you need the recipient_id (will be provided by the url param).
def message_params
params.require(:message).permit(:subject, :content)
end
Give that a try.
I haven't an issue where I can't seem to update or modify a database column in rails 3. I've never seen anything like this before and as such am sure it's something small that I'm overlooking. Please help!
IRB Output:
ruby-1.9.2-p318 :002 > User.all
User Load (0.1ms) SELECT "users".* FROM "users"
=> []
ruby-1.9.2-p318 :003 > User.create( :login => "dummy", :password => "foobar", :password_
confirmation => "foobar", :role => "user", :email => "dummy#email.com" )
(0.1ms) begin transaction
User Exists (0.1ms) SELECT 1 FROM "users" WHERE "users"."login" = 'dummy' LIMIT 1
User Exists (0.0ms) SELECT 1 FROM "users" WHERE "users"."email" = 'dummy#email.com' L
IMIT 1
SQL (0.8ms) INSERT INTO "users" ("created_at", "email", "hashed_password", "login", "
role", "salt", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["created_at", Thu, 05 Apr 2
012 02:21:00 UTC +00:00], ["email", "dummy#email.com"], ["hashed_password", "6416111c47f
a52ddfbde9e539ee6e369807bdeab"], ["login", "dummy"], ["role", nil], ["salt", "1LTzevgRHt
"], ["updated_at", Thu, 05 Apr 2012 02:21:00 UTC +00:00]]
(61.5ms) commit transaction
=> #<User id: 3, login: "dummy", role: nil, hashed_password: "6416111c47fa52ddfbde9e539
ee6e369807bdeab", email: "dummy#email.com", salt: "1LTzevgRHt", created_at: "2012-04-05
02:21:00", updated_at: "2012-04-05 02:21:00">
ruby-1.9.2-p318 :004 > u = User.first
User Load (0.2ms) SELECT "users".* FROM "users" LIMIT 1
=> #<User id: 3, login: "dummy", role: nil, hashed_password: "6416111c47fa52ddfbde9e539
ee6e369807bdeab", email: "dummy#email.com", salt: "1LTzevgRHt", created_at: "2012-04-05
02:21:00", updated_at: "2012-04-05 02:21:00">
ruby-1.9.2-p318 :005 > u.role
=> nil
ruby-1.9.2-p318 :006 > u.role = "foo"
=> "foo"
ruby-1.9.2-p318 :007 > u.role
=> "foo"
ruby-1.9.2-p318 :008 > u
=> #<User id: 3, login: "dummy", role: nil, hashed_password: "6416111c47fa52ddfbde9e539
ee6e369807bdeab", email: "dummy#email.com", salt: "1LTzevgRHt", created_at: "2012-04-05
02:21:00", updated_at: "2012-04-05 02:21:00">
Migration:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.column :login, :string
t.column :role, :string
t.column :hashed_password, :string
t.column :email, :string
t.column :salt, :string
t.timestamps
end
end
end
Schema:
ActiveRecord::Schema.define(:version => 20120318205424) do
create_table "users", :force => true do |t|
t.string "login"
t.string "role"
t.string "hashed_password"
t.string "email"
t.string "salt"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
Model:
require 'digest/sha1'
class User < ActiveRecord::Base
validates_length_of :login, :within => 3..40
validates_length_of :password, :within => 4..40
validates_presence_of :login, :email, :password, :password_confirmation, :salt
validates_uniqueness_of :login, :email
validates_confirmation_of :password
validates_format_of :email, :with => /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i, :message => "Invalid email"
attr_accessor :password, :password_confirmation, :role
attr_protected :id, :salt
def self.random_string(len)
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
newpass = ""
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
return newpass
end
def password=(pass)
#password=pass
self.salt = User.random_string(10) if !self.salt?
self.hashed_password = User.encrypt(#password, self.salt)
end
def self.encrypt(pass, salt)
Digest::SHA1.hexdigest("#{pass}#{salt}")
end
def self.authenticate(login, pass)
u=find(:first, :conditions=>["login = ?", login])
return nil if u.nil?
if User.encrypt(pass, u.salt)==u.hashed_password
# edits wont save without this
u.password=u.password_confirmation=pass
return u
end
nil
end
def send_new_password
new_pass = User.random_string(10)
self.password = self.password_confirmation = new_pass
self.save
Notification.deliver_forgot_password(self.email, self.login, new_pass)
end
def admin?
(self.role == "admin")
end
end
SQLite Update, to show it works:
sqlite> select * from users;
3|dummy||6416111c47fa52ddfbde9e539ee6e369807bdeab|dummy#email.com|1LTzevgRHt|2012-04-05 02:21:00.752890|2012-04-05 02:21:00.752890
sqlite> select role from users;
sqlite> select role from users where login = "dummy";
sqlite> update users set role = "user" where login = "dummy";
sqlite> select role from users where login = "dummy";
user
sqlite> select * from users;
3|dummy|user|6416111c47fa52ddfbde9e539ee6e369807bdeab|dummy#email.com|1LTzevgRHt|2012-04-05 02:21:00.752890|2012-04-05 02:21:00.752890
I've been messing with this for a while... thanks for any help you can give.
EDIT on request:
ruby-1.9.2-p318 :011 > User.last.update_attributes!(:role => "foo")
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
(0.1ms) begin transaction
User Exists (0.1ms) SELECT 1 FROM "users" WHERE ("users"."login" = 'dummy' AND "users"."id" != 3) LIMIT 1
User Exists (0.1ms) SELECT 1 FROM "users" WHERE ("users"."email" = 'dummy#email.com' AND "users"."id" != 3) LIMIT 1
(0.1ms) rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Password is too short (minimum is 4 characters), Password can't be blank, Password confirmation can't be blank
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/validations.rb:56:in `save!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/attribute_methods/dirty.rb:33:in `save!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:246:in `block in save!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:208:in `transaction'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:293:in `with_transaction_returning_status'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:246:in `save!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/persistence.rb:224:in `block in update_attributes!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:208:in `transaction'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:293:in `with_transaction_returning_status'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/persistence.rb:222:in `update_attributes!'
from (irb):11
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/railties-3.2.2/lib/rails/commands/console.rb:47:in `start'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/railties-3.2.2/lib/rails/commands/console.rb:8:in `start'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/railties-3.2.2/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'ruby-1.9.2-p318 :012 > User.last.update_attributes!(:role => "foo")
remove :role from this line attr_accessor :password, :password_confirmation, :role