NoMethodError in Account::PostsController#index - ruby-on-rails

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

Related

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")

Matching users Ruby on Rails and ActiveRecord

[question solved] => I just made a silly mistake and forgot to add #match.save at the end of my method :)
I'm relatively new to RoR and the ActiveRecord architecture. I'm trying to build a simple app that can match 2 users together based on their interests. First here's the schema of my database:
Link to my DB's schema
or if you prefer here's the schema.rb file:
ActiveRecord::Schema.define(version: 20160612080318) do
create_table "conversations", force: :cascade do |t|
t.integer "user1_id"
t.integer "user2_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "conversations", ["user1_id"], name: "index_conversations_on_user1_id", using: :btree
add_index "conversations", ["user2_id"], name: "index_conversations_on_user2_id", using: :btree
create_table "interests", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "matches", force: :cascade do |t|
t.integer "user1_id"
t.integer "user2_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "matches", ["user1_id"], name: "index_matches_on_user1_id", using: :btree
add_index "matches", ["user2_id"], name: "index_matches_on_user2_id", using: :btree
create_table "messages", force: :cascade do |t|
t.text "content"
t.integer "conversation_id"
t.integer "user_id"
t.datetime "read_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "messages", ["conversation_id"], name: "index_messages_on_conversation_id", using: :btree
add_index "messages", ["user_id"], name: "index_messages_on_user_id", using: :btree
create_table "user_interests", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "interest_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.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 "first_name"
t.string "last_name"
t.integer "age"
t.string "avatar_url"
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
add_foreign_key "messages", "conversations"
add_foreign_key "messages", "users"
add_foreign_key "user_interests", "interests"
add_foreign_key "user_interests", "users"
end
Just to test my models I didn't take into account the algorithm that will match users based on their interest. So here's my matches_controller.rb:
class MatchesController < ApplicationController
def new
#match = Match.new
end
def create
#match = Match.new(match_params)
#match.user1_id = current_user.id
#match.user2_id = User.first.id
end
private
def match_params
params.require(:match).permit(:user1_id, :user2_id)
end
end
my match model:
class Match < ActiveRecord::Base
belongs_to :user1, class_name: "User"
belongs_to :user2, class_name: "User"
end
and finally my user model:
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 :user_interests, dependent: :destroy
has_many :interests, through: :user_interests, dependent: :destroy
has_many :messages, dependent: :destroy
has_many :matches, dependent: :destroy
def conversations
Conversation.includes(:messages)
.where("user1_id = :id OR user2_id = :id", id: id)
.order("messages.created_at DESC")
end
def other_user(conversation)
conversation.users.include?(self) ? conversation.other_user(self) : nil
end
def unread_conversations
conversations.select { |c| c.unread_messages?(self) }
end
def unread_conversations_count
unread_conversations.count
end
def unread_conversations?
unread_conversations_count > 0
end
def one_avatar_url
avatar_url ? avatar_url : "http://placehold.it/64x64"
end
end
I've tried to test my Match.create method in the console but got only nil for user1_id and user2_id. I've been looking all day long everywhere without being able to pinpoint what's wrong with my code.
Thanks a lot for helping me on this issue :)

Ruby on Rails SQLite3::ConstraintException: NOT NULL constraint failed:

I am developing a simple app where a user can add a subject to a cart. Before I add the authentication I was able to add a subject to the cart but as I want a user to be able to has access to just his/her cart I used Devise to create User with authentication. Now, when I click on the button to add a subject to the cart I have the following error:
This is a snapshot of the error I get: 1
SQLite3::ConstraintException: NOT NULL constraint failed: carts.user_id: INSERT INTO "carts" ("created_at", "updated_at") VALUES (?, ?)
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
private
def current_cart
Cart.find(params[:user_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
params[:user_id] = cart.id
cart
end
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_one :cart
end
class Cart < ActiveRecord::Base
belongs_to :user
has_many :line_items, dependent: :destroy
scope :user_carts, ->(user) { where(['user_id= ?', user.id]) }
end
class AddUsersToCarts < ActiveRecord::Migration
def up
add_reference :carts, :user, index: true
Cart.reset_column_information
user = User.first
Cart.all.each do |cart|
cart.user_id = user.id
cart.save!
end
change_column_null :carts, :user_id, false
add_foreign_key :carts, :users
end
def down
remove_foreign_key :carts, :users
remove_reference :carts, :user, index: true
end
end
Edit: I added the schema.rb below:
ActiveRecord::Schema.define(version: 20151210213408) do
create_table "carts", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id", null: false
end
add_index "carts", ["user_id"], name: "index_carts_on_user_id"
create_table "line_items", force: :cascade do |t|
t.integer "subject_id"
t.integer "cart_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "subjects", force: :cascade do |t|
t.string "title", null: false
t.string "code", null: false
t.text "description", null: false
t.integer "credits", null: false
t.string "lecturer", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "subjects", ["title"], name: "index_subjects_on_title", unique: true
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
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
You current_cart method does not make much sense.
You cannot find the user's cart by calling Cart.find(params[:user_id]), because that looks for a cart by an id (not by an user_id).
Cart.create fails, because you do not provide an user_id that is required (your database migrations says that the filed cannot be null).
Furthermore, params[:user_id] = cart.id changes the params hash, but not the new cart.
Change that method to something like this (using find_or_create_by) and use the current_user.id instead of params[:user_id]:
def current_cart
Cart.find_or_create_by(user_id: current_user.id)
end

NoMethodError: undefined method `user' for has_many :through Association

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

Issue with belongs_to and user (devise)

I'm new to RoR, and I would like to develop an app, but I have an issue with the belongs_to association. I am using devise for the authentication of my users, and I have an object called timesheet, I followed several tutorials and read a lot of forums but unfortunately user_id remains null in my db, so I do not know where does the problem come from.
If you can tell how to fix it, any links that can helps me, that would be great.
Schema.rb:
ActiveRecord::Schema.define(version: 20150128160116) do
create_table "timesheets", force: true do |t|
t.date "date"
t.time "working_start_time"
t.time "working_end_time"
t.integer "breaks"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "timesheets", ["user_id"], name: "index_timesheets_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.integer "current_sign_in_ip"
t.integer "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
timesheets_controller.rb
class TimesheetsController < ApplicationController
layout 'application'
def show
#timesheet=Timesheet.find(params[:id])
end
def index
#timesheet = Timesheet.all
end
def new
#timesheet = Timesheet.new
end
def create
#timesheet = Timesheet.create(timesheet_params)
redirect_to new_timesheet_path
end
def edit
#timesheet=Timesheet.find(params[:id])
end
def update
#timesheet = Timesheet.find(params[:id])
#timesheet.update_attributes(timesheet_params)
redirect_to student_table_path
end
user.rb model
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 :timesheets
end
Timesheet.rb model
class Timesheet < ActiveRecord::Base
belongs_to :user
validates :user_id, :presence => true
end
Thanks in advance.
It will stay null because you are not using it in the timesheetsController, your create action should be like this :
def create
#timesheet = current_user.timesheets.build(timesheet_params)
redirect_to new_timesheet_path
end
You have to use that build method to reference the current_user, so the timesheet will have the current_user in the user_id field.

Resources