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.
Related
I am new to rails and currently working on a dating application as a portfolio project. However, on my home page, I want to be able to display/render Male or Female data based on the gender of the current_user. That is if the logged-in user is a male, he will only be able to view people of the opposite gender since it's a dating application.
I am using Devise gem and included a custom field called gender. Please, someone should help me with how to do this.
class UsersController < ApplicationController
def index
#user = current_user
#users = User.all
end
def show
#user = User.find(params[:id])
end
User Table
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.text "short_bio"
t.string "gender"
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"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "like"
t.string "image_url"
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 Model
class User < ApplicationRecord
has_one_attached :image
has_many_attached :pictures
has_many :messages
has_many :likes
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :validatable, :trackable
# validates :short_bio, presence: true, length: {maximum: 500}
validates :email, presence: true, uniqueness: { case_sensitive: false }, length: {minimum: 5, maximum: 50}
end
You can only load users with the opposite gender than the current user like this:
#users = User.where.not(gender: current_user.gender)
Probably you need in the model two columns. It is just example as idea
You can use gender (it's not binary) instead of sex
You can use other data type of course
t.integer :sex
t.integer :look_for_sex
And for example:
0 -- female, 1 -- male
And then
User.where(sex: current_user.look_for_sex, look_for_sex: current_user.sex)
will return only users that current user want to date
Thank you for all that responded. I didn't have to refactor my code but just added the code below and that fixed my problem:
#users = current_user == 'Male' ? User.where(gender: 'Male') : User.where(gender: 'Female')
In this case, if the current user is a 'Male', he will only have access to 'Female' and vice versa.
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
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
I used devise to create my users and I am trying to get the user_id to save in the events table when I create an event, I keep getting the error "cant find user without id". Not sure what the problem is any pointers would be greatly appreciated.
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_presence_of :first_name
validates_presence_of :last_name
validates_presence_of :email
validates_presence_of :encrypted_password
validates_presence_of :sign_in_count
has_many :events
end
class Event < ActiveRecord::Base
validates_presence_of :name
validates_presence_of :description
belongs_to :user
has_many :reviews
end
class EventsController < ApplicationController
def index
#events = Event.all
end
def new
#event = Event.new
end
def create
#user = User.find(params[:user_id])
#event = #user.events.build(event_params)
end
def show
#event = Event.find(params[:id])
end
protected
def event_params
params.require(:event).permit(:name, :event_key, :location, :date, :event_url, :description, :time,
:event, :user_id)
end
end
Here is my schema
ActiveRecord::Schema.define(version: 20131226220750) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "events", force: true do |t|
t.string "name", null: false
t.string "location"
t.string "event_url"
t.string "description", null: false
t.integer "user_id"
t.datetime "time"
t.datetime "event_date"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "event_key", null: false
end
add_index "events", ["event_key"], name: "index_events_on_event_key", unique: true, using: :btree
create_table "reviews", force: true do |t|
t.string "feedback_comments"
t.integer "rating", null: false
t.integer "event_id"
t.datetime "created_at"
t.datetime "updated_at"
end
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"
t.string "first_name", null: false
t.string "last_name", null: false
t.string "twitter_handle"
t.string "linked_in_url"
t.string "phone_number"
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
end
Have you looked at params[:user_id] to see if it is what you think it is? I'm pretty sure params[:user_id] will be nil.
Let us look at your params handling:
def event_params
params.require(:event).permit(:name, :event_key, :location, :date, :event_url, :description, :time, :event, :user_id)
end
The require method will look for params[:event] and return it if found. Then permit will look for :name, :event_key, ..., :user_id within params[:event]. So your :user_id is probably params[:event][:user_id] rather than params[:user_id]. The result is that you're saying:
#user = User.find(nil)
and find doesn't want to hear about nils.
This should work better:
def create
event = event_params
#user = User.find(event[:user_id])
#event = #user.events.build(event)
end
If #user is supposed to be the current user all the time then you'd want to get that out of current_user rather than params:
def create
#user = current_user
#event = #user.events.build(event_params)
end
#...
def event_params
params.require(:event).permit(:name, :event_key, :location, :date, :event_url, :description, :time, :event)
# No more :user_id up there
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.