I've attempted to create a has_many :through Association in my rails application, however I get an error when I do the following in the rails console.
2.0.0-p481 :001 > #group = Group.first
Group Load (0.2ms) SELECT "groups".* FROM "groups" ORDER BY "groups"."id" ASC LIMIT 1
=> #<Group id: 1, name: "First Group", description: "Woo", created_at: "2015-02-06 22:19:47", updated_at: "2015-02-06 22:19:47">
2.0.0-p481 :002 > #group.user
NoMethodError: undefined method `user' for #<Group:0x00000004d53eb0>
from /home/jon/.rvm/gems/ruby-2.0.0-p481/gems/activemodel-4.0.2/lib/active_model/attribute_methods.rb:439:in `method_missing'
from /home/jon/.rvm/gems/ruby-2.0.0-p481/gems/activerecord-4.0.2/lib/active_record/attribute_methods.rb:155:in `method_missing'
from (irb):2
from /home/jon/.rvm/gems/ruby-2.0.0-p481/gems/railties-4.0.2/lib/rails/commands/console.rb:90:in `start'
from /home/jon/.rvm/gems/ruby-2.0.0-p481/gems/railties-4.0.2/lib/rails/commands/console.rb:9:in `start'
from /home/jon/.rvm/gems/ruby-2.0.0-p481/gems/railties-4.0.2/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
My Models:
User:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
before_create :do_mailchimp
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :memberships
has_many :groups, through: :memberships
def do_mailchimp
gb = Gibbon::API.new("API")
gb.lists.subscribe({:id => 'ID',
:email => {:email => self.email },:double_optin => false})
end
end
Group:
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, through: :memberships
end
Membership:
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
My Migrations:
DeviseCreateUsers:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
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
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
CreateGroups:
class CreateGroups < ActiveRecord::Migration
def change
create_table :groups do |t|
t.string :name
t.string :description
t.timestamps
end
end
end
CreateMemberships:
class CreateMemberships < ActiveRecord::Migration
def change
create_table :memberships do |t|
t.timestamps
end
end
end
AddUserAndGroupIdToMemberships:
class AddUserAndGroupIdToMemberships < ActiveRecord::Migration
def change
add_column :memberships, :user_id, :integer
add_index :memberships, :user_id
add_column :memberships, :group_id, :integer
add_index :memberships, :group_id
end
end
My Schema:
ActiveRecord::Schema.define(version: 20150206225251) do
create_table "groups", force: true do |t|
t.string "name"
t.string "description"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "memberships", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.integer "group_id"
end
add_index "memberships", ["group_id"], name: "index_memberships_on_group_id"
add_index "memberships", ["user_id"], name: "index_memberships_on_user_id"
create_table "users", force: true 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"
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
end
Thank you for your time hope you can help.
You defined that a Group has_many :users. Therefore a group does not have an user method, but an users method:
#group = Group.first
#group.users #=> returns an array with all users in the first group
#group.users.first #=> returns the first user in the first group
Related
Before I start, I should say I have already checked out Rails 5.1.: destroy records in "has_many: through" association with restriction and has_many through association dependent destroy under condition of who called destroy without results.
My app consist in USERS that has_one EMPRESA.
An EMPRESA may have several TAGS
A TAG may have several EMPRESAS (To do this I have used has_many :through)
My case: I got this screen error:
And I know the origin of this error is because I'm trying to destroy items with pending references. But I can't identify th issue.
By looking at server console I can guess the problem involve empresa, tag, and tagging.
Models involved
class Empresa < ApplicationRecord
skip_callback :validate, after: :create
after_initialize :set_default_plan, :if => :new_record?
attr_accessor :tag_list
enum plan: [:noplan, :basic, :plus, :premium]
belongs_to :user
belongs_to :category, optional: true
has_many :promos, dependent: :destroy
has_many :taggings, dependent: :destroy
has_many :tags, through: :taggings
mount_uploader :logo, LogoUploader
mount_uploaders :fotos, FotosUploader
def tag_list
tags.join(", ")
end
def tag_list=(names)
tag_names = names.split(",").collect {|str| str.strip.downcase}.uniq
new_or_existing_tags = tag_names.collect {|tag_name| Tag.find_or_create_by(name: tag_name)}
self.tags = new_or_existing_tags
end
def set_default_plan
self.plan ||= :noplan
end
end
class Tag < ApplicationRecord
has_many :empresas, through: :taggings
has_many :taggings, dependent: :destroy
def to_s
name
end
end
class Tagging < ApplicationRecord
belongs_to :empresa
belongs_to :tag
end
class Category < ApplicationRecord
validates :name, presence: true, length:{ minimum: 3 }, uniqueness: true
has_many :empresas, dependent: :nullify
end
class User < ApplicationRecord
enum role: [:user, :editor, :admin, :superadmin]
after_initialize :set_default_role, :if => :new_record?
has_one :empresa, dependent: :destroy
has_many :incidents, dependent: :destroy
has_many :comments, dependent: :destroy
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
def set_default_role
self.role ||= :user
end
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
schema.rb (irrelevant tables removed)
ActiveRecord::Schema.define(version: 20180531033550) do
enable_extension "plpgsql"
create_table "empresas", force: :cascade do |t|
t.string "logo"
t.string "name"
t.text "description"
t.text "excerpt"
t.string "address"
t.string "web"
t.string "email"
t.string "tel"
t.string "video"
t.json "fotos"
t.integer "plan", default: 0
t.float "mlon"
t.float "mlat"
t.string "schedule0"
t.string "schedule1"
t.string "schedule2"
t.string "schedule3"
t.string "schedule4"
t.string "schedule5"
t.string "schedule6"
t.string "schedule7"
t.string "schedule8"
t.string "schedule9"
t.string "schedule10"
t.string "schedule11"
t.string "schedule12"
t.string "schedule13"
t.string "schedule14"
t.string "schedule15"
t.string "schedule16"
t.string "schedule17"
t.string "schedule18"
t.string "schedule19"
t.string "schedule20"
t.string "schedule21"
t.string "schedule22"
t.string "schedule23"
t.string "schedule24"
t.string "schedule25"
t.string "schedule26"
t.string "schedule27"
t.integer "tag_id"
t.integer "offer_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id"
t.index ["category_id"], name: "index_empresas_on_category_id", using: :btree
end
create_table "taggings", force: :cascade do |t|
t.integer "empresa_id"
t.integer "tag_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["empresa_id"], name: "index_taggings_on_empresa_id", using: :btree
t.index ["tag_id"], name: "index_taggings_on_tag_id", using: :btree
end
create_table "tags", 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 "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.integer "creditos", default: 0, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "empresa_id"
t.integer "role"
t.string "first_name"
t.string "last_name"
t.date "birthdate"
t.string "dni"
t.string "phone"
t.string "address"
t.string "gender"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
t.index ["empresa_id"], name: "index_users_on_empresa_id", using: :btree
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
add_foreign_key "comments", "incidents"
add_foreign_key "comments", "users"
add_foreign_key "incidents", "users"
add_foreign_key "promos", "empresas"
add_foreign_key "taggings", "empresas"
add_foreign_key "taggings", "tags"
add_foreign_key "users", "empresas"
end
You do not need empresa_id in users.
Remove the referential integrity and column via:
rails g migration remove_constraint_from_users
Edit the newly created migration file to add the following in def change block
def change
remove_foreign_key :users, :empresas
remove_column :users, :empresa_id
end
I understand the cause of a Stack Level Too Deep error. I am failing to spot where/why it is occurring in my code base.
I've implemented a multi-model, multi-step wizard. The first two models (User and Company) are working, it is when I attempt to add in the third (Address) I get the error.
I suspect the error is related to the associations between the models, although I've failed to debug.
The code snippets below function correctly except when I add the 3 lines (marked with comments in the snippet) too the file app/wizards/user_wizard/step1.rb.
Relevant Models
app/models/company.rb
class Company < ActiveRecord::Base
include Validatable::Company
# Associations:
has_many :addresses, inverse_of: :company
accepts_nested_attributes_for :addresses, reject_if: :all_blank
has_many :employees, inverse_of: :company
accepts_nested_attributes_for :employees, reject_if: :all_blank
has_many :licenses, inverse_of: :company
accepts_nested_attributes_for :licenses, reject_if: :all_blank
has_many :vehicles, inverse_of: :company
accepts_nested_attributes_for :vehicles, reject_if: :all_blank
has_one :user, inverse_of: :company
end
app/models/address.rb
class Address < ActiveRecord::Base
# Associations:
belongs_to :company, inverse_of: :addresses
has_many :licenses, inverse_of: :address
accepts_nested_attributes_for :licenses, reject_if: :all_blank
has_many :initial_analyses, inverse_of: :address
accepts_nested_attributes_for :initial_analyses, reject_if: :all_blank
end
app/models/user.rb
class User < ActiveRecord::Base
include SoftDeletable
include Validatable::User
# Constants:
MARKER_ATTRIBUTES = %w[user_name].freeze # get marked with '(deleted)'
DEPENDANT_CHILDREN = %w[none].freeze # child resources to be deleted
# Associations:
belongs_to :role, inverse_of: :users
belongs_to :company, inverse_of: :user
accepts_nested_attributes_for :company, reject_if: :all_blank
has_many :auto_quotes, inverse_of: :user
end
db/schema.rb
ActiveRecord::Schema.define(version: 20170616131833) do
create_table "addresses", force: :cascade do |t|
t.integer "company_id"
t.text "site_name"
t.string "premises_code"
t.string "exempt_premises_code"
t.text "address"
t.string "city"
t.string "county"
t.string "sic_code"
t.string "postcode"
t.string "country"
t.boolean "sic_update"
t.boolean "deleted", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
end
create_table "companies", force: :cascade do |t|
t.string "company_name"
t.string "registration_number"
t.string "type_of_business"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
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.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token"
t.datetime "locked_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "user_name"
t.datetime "deleted_at"
t.integer "role_id"
t.integer "company_id"
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.integer "invited_by_id"
t.string "invited_by_type"
t.integer "invitations_count", default: 0
end
add_index "users", ["company_id"], name: "index_users_on_company_id", unique: true
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true
add_index "users", ["invitations_count"], name: "index_users_on_invitations_count"
add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id"
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index "users", ["unlock_token"], name: "index_users_on_unlock_token", unique: true
end
Wizards
app/wizards/user_wizard/base.rb
module UserWizard
class Base
include ActiveModel::Model
STEPS = %w[step1 step2].freeze
attr_accessor :user
delegate(*::User.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :user)
def initialize(user_attributes)
#user = ::User.new(user_attributes)
end
end
end
app/wizards/user_wizard/step1.rb
module UserWizard
class Step1 < UserWizard::Base
include Validatable::Company
attr_accessor :company
# One of 3 lines triggering circular reference by adding in Address model
attr_accessor :address
delegate(*::Company.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company)
# One of 3 lines triggering circular reference by adding in Address model
delegate(*::Address.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :address)
def initialize(user_attributes)
super
#company = #user.build_company
# One of 3 lines triggering circular reference by adding in Address model
#address = #user.company.addresses.build
end
end
end
app/wizards/user_wizard/step2.rb
ommitted as it is irrelevant. code fails before ever instantiating this class
address has an address attribute. So the delegate method is trying to create a method address that will be delegated to address.
I'd suggest this:
module UserWizard
class Step1 < UserWizard::Base
include Validatable::Company
attr_accessor :company
# One of 3 lines triggering circular reference by adding in Address model
attr_accessor :company_address
delegate(*::Company.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company)
# One of 3 lines triggering circular reference by adding in Address model
delegate(*::Address.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company_address)
def initialize(user_attributes)
super
#company = #user.build_company
# One of 3 lines triggering circular reference by adding in Address model
#company_address = #user.company.addresses.build
end
end
end
I am trying to use Devise on my User model but when I go into rails console and try User.new I only get:
irb(main):002:0> User.new
=> #<User id: nil, first_name: nil, last_name: nil, email: nil, created_at: nil, updated_at: nil>
Why are the devise columns not showing up?
CreateUsers migration:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.timestamps null: false
end
end
end
AddDeviseToUsers migration:
class AddDeviseToUsers < ActiveRecord::Migration
def self.up
change_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
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
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
# Uncomment below if timestamps were not included in your original model.
# t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
def self.down
# By default, we don't want to make any assumption about how to roll back a migration when your
# model already existed. Please edit below which fields you would like to remove in this migration.
raise ActiveRecord::IrreversibleMigration
end
end
Schema shows the columns are there:
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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"
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
Any ideas?
It's a security feature that Devise has in order to restrict its attributes and the critical information it contains to be exposed to API calls.
You can however override this, you need to override serializable_hash method.
# app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :recoverable, :confirmable, :rememberable, :validatable
...
protected
def serializable_hash(options = nil)
super(options).merge(encrypted_password: encrypted_password, reset_password_token: reset_password_token) # you can keep adding attributes here that you wish to expose
end
end
You can check http://www.rubydoc.info/github/plataformatec/devise/Devise/Models/Authenticatable where a constant is declared to blacklist attributes
BLACKLIST_FOR_SERIALIZATION =[:encrypted_password, :reset_password_token, :reset_password_sent_at, :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at, :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
Hope this answers your question!
If all you want to do it list all the attributes in the Rails console, it is easier to use User.first.serializable_hash(force_except: true)
See http://www.rubydoc.info/github/plataformatec/devise/Devise%2FModels%2FAuthenticatable:serializable_hash
Devise overrides the inspect method to not expose internal attibutes. You can try:
User.new.attributes
or
User.new.encrypted_password
(or whatever attribute you want)
You can check inspect method here
I'm the newbie, my rails version is 4.2.0 and I install three gem devise, cancancan, rolify. When I sign up success, I got this message
NoMethodError in Account::PostsController#index
undefined method `role' for #<User:0x007fd84c2afba8>
def admin?
self.role.name == "admin"
end
end
I guess the problem is users, roles the connection is miss. And I try to modify my user.rb but not work.
This is my app/models/ability.rb code
class Ability
include CanCan::Ability
def initialize(user)
if user.admin?
can :manage, :all
else
can :update, Post do |post|
post.user == user
end
can :destroy, Post do |post|
post.user == user
end
can :create, Post
end
end
end
app/models/user.rb
class User < ActiveRecord::Base
has_many :posts
############################################################
# not work
# belongs_to :users_roles
# has_and_belongs_to_many :roles, :join_tabe => :users_roles
# has_one :users_role
############################################################
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
def admin?
self.role.name == "admin"
end
end
app/models/role.rb
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
validates :resource_type,
:inclusion => { :in => Rolify.resource_types },
:allow_nil => true
scopify
end
When I sign up I will add a role to first sign up user, this is my application_controller.rb
def after_sign_in_path_for(resource)
if resource.is_a?(User)
if User.count == 1
resource.add_role 'admin'
else
resource.add_role 'normal'
end
resource
end
root_path
end
schema.rb
ActiveRecord::Schema.define(version: 20160225105659) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "ckeditor_assets", force: :cascade do |t|
t.string "data_file_name", null: false
t.string "data_content_type"
t.integer "data_file_size"
t.integer "assetable_id"
t.string "assetable_type", limit: 30
t.string "type", limit: 30
t.integer "width"
t.integer "height"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "ckeditor_assets", ["assetable_type", "assetable_id"], name: "idx_ckeditor_assetable", using: :btree
add_index "ckeditor_assets", ["assetable_type", "type", "assetable_id"], name: "idx_ckeditor_assetable_type", using: :btree
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"
end
create_table "roles", force: :cascade do |t|
t.string "name"
t.integer "resource_id"
t.string "resource_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree
add_index "roles", ["name"], name: "index_roles_on_name", using: :btree
create_table "travel_events", force: :cascade do |t|
t.string "title"
t.datetime "start_date"
t.datetime "end_date"
t.text "note"
t.integer "travel_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "travels", force: :cascade do |t|
t.string "title"
t.datetime "start_date"
t.datetime "end_date"
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.string "name"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "users_roles", id: false, force: :cascade do |t|
t.integer "user_id"
t.integer "role_id"
end
add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree
end
I think you forgot to add
has_one :users_role
in user.rb
I find the answer, but I'm not sure the question is table's relationship.
I remove my user.rb's admin method
user.rb
class User < ActiveRecord::Base
rolify
has_many :posts
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# def admin?
# self.role.name == "admin"
# end
end
And modify ability.rb
ability.rb
class Ability
include CanCan::Ability
def initialize(user)
# if user.admin?
if user.has_role?(:admin) # modify this line
can :manage, :all
else
can :update, Post do |post|
post.user == user
end
can :destroy, Post do |post|
post.user == user
end
can :create, Post
can :read, Post
end
end
end
So, the index I'm referring to is in songs#index.html.erb.
I'd like to add a line like this:
posted by <%= song.user.email %> <%= time_ago_in_words(song.created_at) + " ago" %>
which at the moment is returning:
undefined method `email' for nil:NilClass
Song.rb snippit
class Song < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
acts_as_voteable
belongs_to :user, class_name: User, foreign_key: :user_id
has_many :comments, :dependent => :destroy
has_many :genre_songs
has_many :genres, through: :genre_songs
User.rb snippit
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :omniauthable,
:recoverable, :rememberable, :trackable, :validatable
has_many :songs
has_many :comments
schema snippits
create_table "users", id: false, force: true do |t|
t.integer "id", null: false
t.string "email", default: ""
t.string "encrypted_password", default: ""
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
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"
t.datetime "updated_at"
t.boolean "admin"
t.string "provider"
t.string "uid", null: false
t.string "username"
end
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "songs", force: true do |t|
t.string "title"
t.string "artist"
t.text "url"
t.string "track_file_name"
t.string "track_content_type"
t.integer "track_file_size"
t.datetime "track_updated_at"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "plusminus"
t.string "slug"
end
add_index "songs", ["slug"], name: "index_songs_on_slug", unique: true, using: :btree
It seems one of your songs you list in index doesn't have its associated user, so the song.user returns nil.
To avoid this you should validate presence of user in Song model, or check if user exists in view, like this:
<% if song.user %>
posted by <%= song.user.email %> <%= time_ago_in_words(song.created_at) + " ago" %>
<% end %>
The approach depends on your application logic.