Getting undefined method `add_role' with Rails 6, Rolify using UUID - ruby-on-rails

I just added rolify to my Rails 6 app, which is using UUID for all tables.
After the initial errors I found that I need to change my migrations slightly to deal with the UUID. I am also using a model named 'Person' instead of the default 'User'.
I have tried restarting my server (several times) but I still get the following:
2.6.2 :002 > p.add_role :admin
Traceback (most recent call last):
1: from (irb):2
NoMethodError (undefined method `add_role' for #Person::ActiveRecord_Relation:0x00007fe37ec29408>)
2.6.2 :003 >
Here are the applicable models:
role.rb
class Role < ApplicationRecord
has_and_belongs_to_many :people, :join_table => :people_roles
belongs_to :resource,
:polymorphic => true,
:optional => true
validates :resource_type,
:inclusion => { :in => Rolify.resource_types },
:allow_nil => true
scopify
end
person.rb
class Person < ApplicationRecord
rolify
def full_name
"#{self.last_name}, #{self.first_name}"
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :trackable
end
applicable schema:
create_table "people", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "last_name"
t.string "first_name"
t.string "gender"
t.uuid "personable_id"
t.string "personable_type"
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.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.integer "failed_attempts", default: 10, null: false
t.string "unlock_token"
t.datetime "locked_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "type"
t.index ["email"], name: "index_people_on_email", unique: true
t.index ["reset_password_token"], name: "index_people_on_reset_password_token", unique: true
t.index ["unlock_token"], name: "index_people_on_unlock_token", unique: true
end
create_table "people_roles", id: false, force: :cascade do |t|
t.uuid "person_id"
t.uuid "role_id"
t.index ["person_id", "role_id"], name: "index_people_roles_on_person_id_and_role_id"
end
create_table "roles", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.uuid "resource_id"
t.string "resource_type"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"
t.index ["name"], name: "index_roles_on_name"
end
Any help on this would be much appreciated!

Your problem is that p is not a Person but a collection of Person objects as indicated by ActiveRecord_Relation.
If you would like all of those people to have the admin role then it would be
p.each {|person| person.add_role :admin }
Otherwise you will need to change the code that populates p to return a single Person object. For instance if you are populating p as
p = Person.where(uuid: some_uuid)
Then change this to
p = Person.find_by(uuid: some_uuid) # or Person.find_by_uuid(some_uuid)
find_by will return an instance of the class (or nil none are found) by selecting the first record where the condition is true. Since uuid by virtue is unique this should not be an issue.

Related

How would i create an instance of a object after a user creates their account using devise

As of right now i have the user model from the Devise gem, and i have also created a Player model to store information that i need for my app. All I'm trying to do is make a new Player whenever a User creates an account. The Player model has 3 columns - one for the user_id, one for the game_id and one for the deck_id.
#schema.rb
create_table "games", force: :cascade do |t|
t.text "players"
t.integer "player_count"
t.boolean "rogue", default: true
t.boolean "wizard", default: true
t.boolean "paladin", default: true
t.boolean "barbarian", default: true
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "last_selected_deck"
end
create_table "players", force: :cascade do |t|
t.integer "user_id", null: false
t.integer "game_id"
t.integer "company_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["company_id"], name: "index_players_on_company_id"
t.index ["game_id"], name: "index_players_on_game_id"
t.index ["user_id", "game_id"], name: "index_players_on_user_id_and_game_id", unique: true
t.index ["user_id"], name: "index_players_on_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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "company_id", null: false
t.string "username"
t.integer "game_id"
t.index ["company_id"], name: "index_users_on_company_id"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
#user.rb
class User < ApplicationRecord
after_create :create_player
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
belongs_to :company
has_one :player, dependent: :destroy
has_one :game, through: :player
def create_player
#code
end
end
i thought i could create a method inside the user.rb model that should be executed after creation, but it doesn't seem to work
You have declared the user-player association, so you can do something like this:
def create_player
self.player.create!
# Player.create!(user_id: self.id) # without taking account assiciation
end
Hope it helps!

undefined method `to_sym' for nil:NilClass RoR

This is my first publication in stack overflow, I hope you can help me.
I'm working with RoR and PostgreSQL, gem 'devise'.
In rails console I am trying to delete data from the "Competitor" table, but I have the following error and I have not been able to solve it.
2.4.1 :006 > c.destroy(c)
ActiveRecord::UnknownPrimaryKey: Unknown primary key for table competitors in model Competitor.
This is my competitors table, which it's was generate with model of gem devise
create_table "competitors", id: false, 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.bigint "rut"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.string "lastname"
t.integer "phone"
t.date "dateOfBirth"
t.boolean "gender"
t.string "numberSerie"
t.string "otp_secret_key"
t.integer "otp_module", default: 0
t.index ["email"], name: "index_competitors_on_email", unique: true
t.index ["reset_password_token"], name: "index_competitors_on_reset_password_token", unique: true
t.index ["rut"], name: "index_competitors_on_rut", unique: true
endere
and this is the model
class Competitor < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :raffle_registers, primary_key: 'rut', foreign_key: 'rutCompetitors'
has_many :accountpays
has_one :found
#otp model to make it use TFA
has_one_time_password
enum otp_module: { disabled: 0, enabled: 1 }, _prefix: true
attr_accessor :otp_code_token
end
You generated the competitors table without primary key. Checkout this line:
create_table "competitors", id: false, force: :cascade do |t|
The id: false is your issue. Check the migration to create the competitors table and set a primary key (or create a new migration adding a primary key to it).
Useful resource: https://stackoverflow.com/a/10079409/740394

My sqlite database is not able to persist anything?

I have a Rails Api with models, controllers, and serializers. The database is set up, and I have made several migrations, all of which have resulted in corresponding changes to the schema. However, nothing is being persisted to the database, either in the rails console or from the seed data. For instance, when I try to run User.create in the console, I see this message appear:
2.3.3 :003 > User.create
(0.1ms) begin transaction
(0.1ms) rollback transaction
=> #<User id: nil, email: "", created_at: nil, updated_at: nil>
Similarly, I have this data in my seeds file:
users = User.create([{ email: 'adam#adam.com' }, { email: 'ryan#ryan.com'
}])
BankAccount.create(name: 'Adams Chase Checking Account', user_id: users.first)
When I run rake db:seed and attempt to call User.all or BankAccount.all in the rails console, I am given an empty array in both cases. I have heard of errors like this being caused by unmet validations on the models, but my models do not have any validations. I am at a loss as to what could be causing this issue. Any help is greatly appreciated! Also, for what it's worth, this project uses Rails 5.1.4, and I have only used 4.x.x previously. Here is the User model (using devise):
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :bank_accounts
has_many :credit_cards
has_many :investments
has_many :loans
has_many :assets
has_many :recurring_payments, through: :bank_accounts
has_many :recurring_payments, through: :credit_cards
has_many :recurring_payments, through: :investments
has_many :recurring_payments, through: :loans
end
And here is the bank account model:
class BankAccount < ApplicationRecord
belongs_to :user
has_many :recurring_payments
accepts_nested_attributes_for :recurring_payments
end
Here is the full schema:
ActiveRecord::Schema.define(version: 20180205231948) do
create_table "assets", force: :cascade do |t|
t.string "name"
t.integer "value"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "bank_accounts", force: :cascade do |t|
t.string "name"
t.integer "balance"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "credit_cards", force: :cascade do |t|
t.string "provider"
t.integer "balance"
t.integer "interest_rate"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "investments", force: :cascade do |t|
t.string "name"
t.integer "value"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "loans", force: :cascade do |t|
t.integer "user_id"
t.integer "interest_rate"
t.integer "remaining_balance"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "recurring_payments", force: :cascade do |t|
t.string "source"
t.boolean "status"
t.date "pay_date"
t.integer "pay_amount"
t.integer "duration"
t.integer "bank_account_id"
t.integer "credit_card_id"
t.integer "loan_id"
t.integer "investment_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name:
"index_users_on_reset_password_token", unique: true
end
end
My guess is this.
users = User.create([{ email: 'adam#adam.com' }, { email: 'ryan#ryan.com' }])
Devise validates the default password before saving (6 characters minimum). Try running this command in console and see if it throws any errors?
user = User.create(email: 'adam#adam.com')
user.errors

Rails rollback transaction for bids

Hello I'm getting a rollback transaction when I try to create a Bid from the rails console. These are my models:
Product Model
class Product < ApplicationRecord
belongs_to :user
belongs_to :category
has_many :ratings
has_many :bids
end
Bid model:
class Bid < ApplicationRecord
belongs_to :products
belongs_to :user
end
User model:
class User < ApplicationRecord
has_many :products
has_many :ratings
has_many :bids
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
And this is my schema:
ActiveRecord::Schema.define(version: 20161231124005) do
create_table "bids", force: :cascade do |t|
t.integer "amount"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "product_id"
t.index ["product_id"], name: "index_bids_on_product_id"
t.index ["user_id"], name: "index_bids_on_user_id"
end
create_table "categories", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "image_url"
t.integer "price"
t.datetime "deadline"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "category_id"
end
create_table "ratings", force: :cascade do |t|
t.integer "rating"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "product_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.string "username"
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
end
Although I tried to create like so: Bid.create(amount: 500, user_id: 1, product_id:6) it doesn't save because of the rollback transaction.
Thanks in advance
The code you posted doesn't really help. You should also add the logs.
Before posting any logs, I'd try b = Bid.new(amount: 500, user_id: 1, product_id: 6) and b.save in the console. After that, do b.errors and see what's causing the rollback.
EDIT: Add .save.
EEDIT: For anyone experiencing the same problem, the issue was with the Bid model referencing a Product wrong.
When using belongs_to, the model should be singular, not plural. Ex: belongs_to: apple not belongs_to: apples

Why do I get an error "wrong number of arguments (given 1, expected 0)" for a search query in Rails?

This line raises the error "wrong number of arguments (given 1, expected 0)". I would really like to know how to get this query to work. Thanks!
#posts = Post.all(:joins => :course, :conditions => "course.name in (#{#user.courses.map(&:name).join(',')})",:order => "posts.created_at DESC")
This is code in my controller:
#user = current_user
#posts = Post.all(:joins => :course, :conditions => "course.name in (#{#user.courses.map(&:name).join(',')})",:order => "posts.created_at DESC")
Here are the models:
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :course
has_many :comments
end
class Course < ActiveRecord::Base
belongs_to :user
has_many :posts
belongs_to :major
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :courses
belongs_to :major
has_many :posts
has_many :comments
accepts_nested_attributes_for :courses, reject_if: :all_blank, allow_destroy: true
end
And here is the schema
create_table "comments", force: :cascade do |t|
t.text "comment"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "post_id"
end
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
create_table "courses", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "major_id"
t.integer "user_id"
end
add_index "courses", ["major_id"], name: "index_courses_on_major_id"
add_index "courses", ["user_id"], name: "index_courses_on_user_id"
create_table "majors", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "posts", 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 "course_id"
end
add_index "posts", ["course_id"], name: "index_posts_on_course_id"
add_index "posts", ["user_id"], name: "index_posts_on_user_id"
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.boolean "admin"
t.string "username"
t.integer "major_id"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["major_id"], name: "index_users_on_major_id"
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index "users", ["username"], name: "index_users_on_username", unique: true
end
The error you are getting in the query is due to the fact that the all method does not expect any parameters, it just retrieves all records for a given model/relation.
What you want to use in this case is the where method from ActiveRecord::QueryMethods.
There is another error, you are using the name of the table in singular on your condition, where it should be plural (courses instead of course).
Also, you could use here the includes method combined with the references method to generate the database join.
So, you would have something like the following:
#posts = Post.includes(:course).where("courses.name IN (#{#user.courses.map(&:name).collect { |s| '#{s}' }.join(',') })").references(:courses).order("posts.created_at DESC")

Resources