User:
class User < ActiveRecord::Base
attr_accessible :email, :username, :password, :password_confirmation, :remember_me
has_many :tasks_users, :dependent => :destroy, :conditions => {:is_owner => true}
has_many :tasks, :through => :tasks_users, :source => :task
Task:
class Task < ActiveRecord::Base
include RankedModel
ranks :sort_order
acts_as_taggable
has_many :tasks_users
has_many :users, :through => :tasks_users
TasksUser:
class TasksUser < ActiveRecord::Base
attr_accessible :is_owner
belongs_to :user
belongs_to :task
validates_uniqueness_of :user_id, :scope => [:user_id, :task_id]
end
They key here is dependent destroy.
Whenever I try to destroy my user, which should destroy the join model, I end up getting this odd sql error:
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 17]]
(0.1ms) begin transaction
ActsAsTaggableOn::Tagging Load (0.1ms) SELECT "taggings".* FROM "taggings" WHERE "taggings"."tagger_id" = 17 AND "taggings"."tagger_type" = 'User'
TasksUser Load (0.1ms) SELECT "tasks_users".* FROM "tasks_users" WHERE "tasks_users"."user_id" = 17 AND "tasks_users"."is_owner" = 't'
Could not log "sql.active_record" event. NoMethodError: undefined method `name' for nil:NilClass
**SQLite3::SQLException: no such column: tasks_users.: DELETE FROM "tasks_users" WHERE "tasks_users"."" = ?**
(0.1ms) rollback transaction
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: tasks_users.: DELETE FROM "tasks_users" WHERE "tasks_users"."" = ?
from /home/steveq/.rvm/gems/ruby-1.9.3-p194#rails32/gems/sqlite3-1.3.7/lib/sqlite3/database.rb:91:in `initialize'
The line with the double asterisk is the line in question - it appears to be searching for a record in "tasks_users"."".
If all I do is change :conditions => {:is_owner => false}, the sql executes without a problem:
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 17]]
(0.1ms) begin transaction
ActsAsTaggableOn::Tagging Load (0.2ms) SELECT "taggings".* FROM "taggings" WHERE "taggings"."tagger_id" = 17 AND "taggings"."tagger_type" = 'User'
TasksUser Load (0.1ms) SELECT "tasks_users".* FROM "tasks_users" WHERE "tasks_users"."user_id" = 17 AND "tasks_users"."is_owner" = 'f'
List Load (0.2ms) SELECT "lists".* FROM "lists" WHERE "lists"."owner_id" = 17
Relationship Load (0.1ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."user_id" = 17
SQL (0.3ms) DELETE FROM "users" WHERE "users"."id" = ? [["id", 17]]
(299.4ms) commit transaction
Any ideas about what's happening here, and why having the condition of is_owner change from true to false allows the query and delete statement to execute?
Thanks
Ugh - Hopefully I can save someone else from banging their heads against this wall for an hour.
Problem was how I specified the :conditions.
It needed to be put in double quotes:
has_many :tasks_users, :dependent => :destroy, :conditions => "is_owner = 'true'"
That was it.
Related
I'm having an issue with Rails ActiveAdmin (quite a novice myself still) where a has_many association (CampaignCountry) is deleting/adding records incorrectly when its select input field :countries is modified and when the parent object (Campaign) fails due to any validation errors:
↳ /Users/JAlva/.rbenv/versions/2.5.8/lib/ruby/gems/2.5.0/gems/activerecord-5.2.5/lib/active_record/log_subscriber.rb:98
CampaignCountry Destroy (0.3ms) DELETE FROM "campaign_countries" WHERE "campaign_countries"."campaign_id" = $1 AND "campaign_countries"."country_id" = $2 [["campaign_id", 53], ["country_id", 1]]
↳ /Users/JAlva/.rbenv/versions/2.5.8/lib/ruby/gems/2.5.0/gems/activerecord-5.2.5/lib/active_record/log_subscriber.rb:98
(0.6ms) COMMIT
↳ /Users/JAlva/.rbenv/versions/2.5.8/lib/ruby/gems/2.5.0/gems/activerecord-5.2.5/lib/active_record/log_subscriber.rb:98
(0.1ms) BEGIN
↳ /Users/JAlva/.rbenv/versions/2.5.8/lib/ruby/gems/2.5.0/gems/activerecord-5.2.5/lib/active_record/log_subscriber.rb:98
Campaign Exists (0.3ms) SELECT 1 AS one FROM "campaigns" WHERE "campaigns"."vanity_url" = $1 AND "campaigns"."id" != $2 LIMIT $3 [["vanity_url", "dummycampaign"], ["id", 53], ["LIMIT", 1]]
↳ /Users/JAlva/.rbenv/versions/2.5.8/lib/ruby/gems/2.5.0/gems/activerecord-5.2.5/lib/active_record/log_subscriber.rb:98
(0.1ms) ROLLBACK
as you can see, CampaignCountry delete is still occuring despite the parent objects eventual ROLLBACK in this example. Ideally, I want the CampaignCountry records to only update after the parent Campaign validations are run and it is found to be valid. Below are the association rules between them:
# Campaign model:
has_many :campaign_countries, dependent: :destroy
has_many :countries, through: :campaign_countries
# CampaignCountry model:
belongs_to :campaign, touch: true
belongs_to :country
# Campaign ActiveAdmin countries field:
permit_params ... country_ids: []
...
f.input :countries, as: :select, multiple: true, collection: Country.pluck(:alpha_code, :id)
Any help is appreciated in understanding why this is occuring as well as a potential fix. Let me know if supplemental information is needed.
i'm using rails 4 and was wondering if anyone could find what's wrong in my code.
I have project model and I created a team model that has a belongs_to - has_one relation with project.
project model:
class CrmProject < ActiveRecord::Base
has_one :crm_team
team model
class CrmTeam < ActiveRecord::Base
belongs_to :crm_project
accepts_nested_attributes_for :crm_project
belongs_to :crm_section
belongs_to :manager, class_name: "User"
has_many :users
accepts_nested_attributes_for :users
end
When submitting the form to create a new team i get this error:
ActiveModel::MissingAttributeError in CrmTeamsController#create
can't write unknown attribute `crm_team_id`
and log from server :
Parameters: {"crm_team"=>{"crm_project"=>"5", "manager"=>"3", "user_ids"=>["", "2"]}, "co
mmit"=>"Create Crm team"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1
[["id", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
(0.1ms) begin transaction
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'email#gmail.com' AND "users"."
id" != 2) LIMIT 1
SQL (0.2ms) INSERT INTO "crm_teams" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2020-03-1
1 07:29:19.735115"], ["updated_at", "2020-03-11 07:29:19.735115"]]
(0.2ms) rollback transaction
Completed 500 Internal Server Error in 9ms (ActiveRecord: 1.0ms)
When you use a has_one relation like this
has_one :crm_team
Rails expects you to add crm_team_id to your crm_project, in order to understand which crm_team is related with crm_project object. Adding it going to solve your problem.
In my opinion defining opposite like this much better in logic. Because in future these teams can have multiple projects.
class CrmProject < ActiveRecord::Base
belongs_to :crm_team
class CrmTeam < ActiveRecord::Base
***has_one/has_many(pick one)*** :crm_project
accepts_nested_attributes_for :crm_project
belongs_to :crm_section
belongs_to :manager, class_name: "User"
has_many :users
accepts_nested_attributes_for :users
end
In my controllers/common/roles_controller.rb I would like to check if particular role (ID) belongs to current_user company users and if not, redirect to errors_path:
def correct_role
role_user = Role.where(:id => params[:id]).select('user_id').first
company_user = current_user.companies.includes(:users)
redirect_to(errors_path) unless company_user.include? role_user.id
end
Definitions:
role_user - finds user ID for particular role ID ("user_id" is column of roles table)
company_user - finds all user ID who belong to companies, which belong to current_user
models/role.rb
belongs_to :user, optional: true, inverse_of: :roles
accepts_nested_attributes_for :user
enum general: { seller: 1, buyer: 2, seller_buyer: 3}, _suffix: true
enum dashboard: { denied: 0, viewer: 1, editer: 2, creater: 3, deleter: 4}, _suffix: true
models/user.rb
#User has roles
has_many :roles
accepts_nested_attributes_for :roles, reject_if: proc { |attributes| attributes[:name].blank? }
# User has many companies
has_many :accounts, dependent: :destroy
has_many :companies, through: :accounts
models/account.rb
class Account < ApplicationRecord
belongs_to :company
belongs_to :user
accepts_nested_attributes_for :company, :user
end
models/company.rb
has_many :accounts, dependent: :destroy
has_many :users, through: :accounts
At the moment with role_user and company_user I can find both ID, however I cannot do the checking part. How do I do that correctly, please? Thank you for any help!
Update
#sajan code give this in console when I open /common/roles/1/edit (current_user ID=1 and should be allowed to edit):
Parameters: {"id"=>"1"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.6ms) SELECT COUNT(*) FROM "companies" INNER JOIN "accounts" ON "companies"."id" = "accounts"."company_id" WHERE "accounts"."user_id" = ? [["user_id", 1]]
(0.3ms) SELECT "roles".id FROM "roles" WHERE "roles"."user_id" = ? [["user_id", 1]]
#Abhishek Kumar code in console gives:
Parameters: {"id"=>"1"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Company Load (0.5ms) SELECT "companies".* FROM "companies" INNER JOIN "accounts" ON "companies"."id" = "accounts"."company_id" WHERE "accounts"."user_id" = ? [["user_id", 1]]
(0.4ms) SELECT "users".id FROM "users" INNER JOIN "accounts" ON "users"."id" = "accounts"."user_id" WHERE "accounts"."company_id" = ? [["company_id", 13]]
Role Load (0.2ms) SELECT "roles"."user_id" FROM "roles" WHERE "roles"."id" = ? ORDER BY "roles"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Update v2
So I'm trying to use this code:
def correct_role
company_user_ids = current_user.companies.map(&:user_ids)
role_user = Role.where(:id => params[:id]).select('user_id').first
unless role_user.user_id.in?(company_user_ids)
redirect_to(errors_path)
end
end
however it redirects to errors_path in any case, this is what I have in console:
Parameters: {"id"=>"1"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Company Load (0.5ms) SELECT "companies".* FROM "companies" INNER JOIN "accounts" ON "companies"."id" = "accounts"."company_id" WHERE "accounts"."user_id" = ? [["user_id", 1]]
(0.4ms) SELECT "users".id FROM "users" INNER JOIN "accounts" ON "users"."id" = "accounts"."user_id" WHERE "accounts"."company_id" = ? [["company_id", 13]]
Role Load (0.3ms) SELECT "roles"."user_id" FROM "roles" WHERE "roles"."id" = ? ORDER BY "roles"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
It seems that a better logic would be to define on the model for the current_user an association through companies and users to roles.
Then you can check:
def correct_role
redirect_to(errors_path) unless current_user.company_user_roles.where(id: params[:id]).exists?
end
It would be a single SQL statement that would return zero or one rows, and execute very quickly with the appropriate indexes in place.
Edit:
To company.rb, add:
has_many :user_roles, through: :users, source: :roles
To user.rb (assuming that current_user is an instance of this model) add:
has_many :company_user_roles, through: :companies, source: :user_roles
Maybe you could do like this:
def correct_role
unless current_user.companies.count > 0 && current_user.role_ids.include?(params[:id])
redirect_to(errors_path)
end
end
I'm new to rails and I want to know how to fetch a one-to-one relationship. I want to fetch users city. In my postgresql database I have:
cities Table:
city:varchar
zipcode: integer
users Table
name:varchar
city_id:int
and in city and user model I have:
class City < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :city
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
I tried the following in my search controller but didnt work, when logged in:
current_user.city
I get the following error
Processing by SearchController#index as HTML
Parameters: {"utf8"=>"✓", "q"=>"", "criteria"=>"1", "commit"=>"Search"}
User Load (1.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 6 ORDER BY "users"."id" ASC LIMIT 1
PG::UndefinedColumn: ERROR: column cities.user_id does not exist
LINE 1: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" =...
^
: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" = $1 LIMIT 1
Completed 500 Internal Server Error in 11ms
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column cities.user_id does not exist
LINE 1: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" =...
^
: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" = $1 LIMIT 1):
why am I suppose to add a user_id column to cities table, when I have cities foreign key in users table? I dont want to add user_id into cities table.
You can use has_one :through association with join table. Some example for you below.
user model:
class User < ActiveRecord::Base
has_one :city, through: :user_city
has_one :user_city
end
city model:
class City < ActiveRecord::Base
belongs_to :user
end
user city join model:
class UserCity < ActiveRecord::Base
belongs_to :city
belongs_to :user
end
migration for join tables:
class JoinUserCity < ActiveRecord::Migration
def change
create_table :user_cities do |t|
t.integer :user_id
t.integer :city_id
end
end
end
Test in rails console:
=> u = User.create
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2014-12-07 15:47:14.595728"], ["updated_at", "2014-12-07 15:47:14.595728"]]
(3.3ms) commit transaction
=> #<User id: 4, created_at: "2014-12-07 15:47:14", updated_at: "2014-12-07 15:47:14">
=> u.city
City Load (0.2ms) SELECT "cities".* FROM "cities" INNER JOIN "user_cities" ON "cities"."id" = "user_cities"."city_id" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
=> nil
=> c = City.create
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "cities" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2014-12-07 15:47:24.535039"], ["updated_at", "2014-12-07 15:47:24.535039"]]
(3.3ms) commit transaction
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
irb(main):004:0> u.city = c
UserCity Load (0.3ms) SELECT "user_cities".* FROM "user_cities" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "user_cities" ("city_id", "user_id") VALUES (?, ?) [["city_id", 1], ["user_id", 4]]
(1.0ms) commit transaction
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
irb(main):005:0> u.save
(0.1ms) begin transaction
(0.1ms) commit transaction
=> true
=> u = User.last
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
=> #<User id: 4, created_at: "2014-12-07 15:47:14", updated_at: "2014-12-07 15:47:14">
=> u.city
City Load (0.2ms) SELECT "cities".* FROM "cities" INNER JOIN "user_cities" ON "cities"."id" = "user_cities"."city_id" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
take a look at the document of has_one and belogns_to,
belongs_to(name, options = {})
Specifies a one-to-one association with another class. This method should only be used if this class
contains the foreign key. If the other class contains the foreign key, then you should use has_one
instead.
as the user table has the foreign key, you should change your model definition like this
class City < ActiveRecord::Base
has_one :user
end
class User < ActiveRecord::Base
belongs_to :city
end
I'm trying to make will_paginate's :order to work with this array:
#posts = current_user.subscribed_tags.map(&:posts).flatten.paginate(:page => params[:page],
per_page => 5,
:order => "created_at DESC")
Right now, it doesn't matter what value I give to :order, posts are ordered by tag (I think the date of creation of the tag). I want them to appear according to the posts creation date. I think the problem is that will_paginate is using the tags as reference and not the posts.
How to solve this issue (Maybe I have to define #posts in another way)?
Additional Information:
Users can subscribe to tags (So in the index page the user only sees posts with tags he or she is subscribe to).
Models:
User model:
class User < ActiveRecord::Base
(Devise)
has_many :posts, :dependent => :destroy
has_many :subscriptions
has_many :subscribed_tags, :source => :tag, :through => :subscriptions
attr_writer :subscribed_tag_names
after_save :assign_subscribed_tags
def subscribed_tag_names
#subscribed_tag_names || subscribed_tags.map(&:name).join(' ')
end
private
def assign_subscribed_tags
#self.subscribed_tags = []
return if #subscribed_tag_names.blank?
#subscribed_tag_names.split(" ").each do |name|
subscribed_tag = Tag.find_or_create_by_name(name)
self.subscribed_tags << subscribed_tag unless subscribed_tags.include?(subscribed_tag)
end
end
end
Tag model:
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :posts, :through => :taggings
has_many :subscriptions
has_many :subscribed_users, :source => :user, :through => :subscriptions
def tag_posts_count
"#{self.name} (#{self.posts.count})"
end
end
Generated SQL:
Processing by PostsController#index as HTML
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
Tag Load (0.5ms) SELECT "tags".* FROM "tags" INNER JOIN "subscriptions" ON "tags"."id" = "subscriptions"."tag_id" WHERE "subscriptions"."user_id" = 2
Post Load (0.7ms) SELECT "posts".* FROM "posts" INNER JOIN "taggings" ON "posts"."id" = "taggings"."post_id" WHERE "taggings"."tag_id" = 6
Post Load (0.6ms) SELECT "posts".* FROM "posts" INNER JOIN "taggings" ON "posts"."id" = "taggings"."post_id" WHERE "taggings"."tag_id" = 10
Post Load (0.7ms) SELECT "posts".* FROM "posts" INNER JOIN "taggings" ON "posts"."id" = "taggings"."post_id" WHERE "taggings"."tag_id" = 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
Tag Load (0.5ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."post_id" = 42
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 4 LIMIT 1
Tag Load (0.5ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."post_id" = 38
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
Comment Load (0.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 52 ORDER BY "comments"."id" DESC LIMIT 1
CACHE (0.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 52 ORDER BY "comments"."id" DESC LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
CACHE (0.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 52 ORDER BY "comments"."id" DESC LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
Tag Load (0.5ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."post_id" = 52
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
Tag Load (0.5ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."post_id" = 55
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
Comment Load (0.7ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 57 ORDER BY "comments"."id" DESC LIMIT 1
CACHE (0.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 57 ORDER BY "comments"."id" DESC LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
CACHE (0.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 57 ORDER BY "comments"."id" DESC LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
Tag Load (0.5ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."post_id" = 57
Rendered layouts/_sidebar.html.erb (12.6ms)
Rendered posts/index.html.erb within layouts/application (314.3ms)
Rendered layouts/_header.html.erb (5.2ms)
Rendered layouts/_footer.html.erb (0.1ms)
Completed 200 OK in 1242ms (Views: 392.8ms | ActiveRecord: 12.5ms)
You are calling paginate on a regular array rather than on a sql result set.
[1,2,3,4].paginate(:page => 1, :per_page => 2) # [1, 2]
current_user.subscribed_tags.map(&:posts) # returns an array
If you are on Rails 3.1 and above:
class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
has_many :subscriptions
has_many :subscribed_tags, :source => :tag, :through => :subscriptions
has_many :subscribed_posts, :source => :posts, :through => :subscribed_tags
end
class Subscription
belongs_to :user
belongs_to :tag
end
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :posts, :through => :taggings
has_many :subscriptions
end
Now you can
current_user.subscribed_posts.paginate(:page => params[:page],
per_page => 5,
:order => "created_at DESC")