Adding user_ids to each article(devise) - ruby-on-rails

I have a user model:
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
has_secure_password
has_many :articles
And my schema for User looks like:
create_table "users", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "password_digest"
t.datetime "created_at"
t.datetime "updated_at"
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
Half of these are from the devise gem. So what I'm trying to accomplish is having each article have an author assigned to it(first_name + last_name).
My article model looks like:
belongs_to :topic
belongs_to :user
def author
"#{self.user_id.first_name} #{self.user_id.last_name}"
end
And my actions in the article controller looks like:
def create
#article = Article.new(article_params)
#article.user = current_user
if #article.save
##article.user = session[:user_id]
flash[:notice] = "Article has been uploaded"
redirect_to(:action => "show", :id => #article.id)
else
flash[:notice] = "Please fill in all fields."
render("new")
end
end
And if I do <p><%=#article.author%></p> in my show view, it has an error that says undefined method - 'first_name'
How do I add authors to each article.

Use self.user.first_name instead of self.user_id.first_name.in your author method
And #article.user = current_user is fine if you want ot use user_id in this case then
use #artilce.user_id = current_user.id

okay here is how you do it:
user.rb
has_many :items
article.rb
belongs_to :user
articles_controller.rb
def create
#article = Article.new(params[:article].permit(:name, ...))
#article.user_id = current_user.id
if #article.save
flash[:notice] = 'article created'
redirect_to #article
else
render 'new'
end
end

Related

How to fill multiple form fields using attribute from another model?

I have 3 models - User, Shipment and Friendship. User can be friends with another user via Friendship-model. User also can create Shipments and can add a Friend-User to it. There is address-attribute in User and Shipment models. I need to give User a possibility to fill that address field in 2 ways at the same form:
By filling the address field manually.
By choosing from select-list a Friend of that User - so the Friends
address-attribute transfers and fills the Shipments adress-attribute
(like ctrl-c/ctrl-v) and User can Submit the form.
I can guess, that AJAX is needed to refresh the content without refreshing the page.
Shipment model:
class Shipment < ActiveRecord::Base
belongs_to :user
belongs_to :friendship
validates :image, presence: true
validates :user_id, presence: true
end
Shipments controller:
class ShipmentsController < ApplicationController
helper_method :shipment, :user
before_action :set_shipment, only: [:show]
before_action :authenticate_user!
before_action :require_same_user, only: [:show]
def index
#shipments = Shipment.all
end
def new
#shipment = Shipment.new
end
def create
#shipment = Shipment.new(shipment_params)
#shipment.user = current_user
if #shipment.save
flash[:success] = "Shipment etc."
redirect_to shipment_path(#shipment)
else
render 'new'
end
end
def show
#shipment = Shipment.find(params[:id])
end
private
def user
#user = current_user
end
def shipment
#shipment = user.shipments.new
end
def shipment_params
params.require(:shipment).permit(:name, :kg, :length, :width, :height,
:adress, :image, :user_id, :friend_id)
end
def set_shipment
#shipment = Shipment.find(params[:id])
end
def require_same_user
if current_user != #shipment.user
flash[:alert] = "Restricted/"
redirect_to root_path
end
end
end
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 :shipments, dependent: :destroy
has_many :friendships
has_many :friends, through: :friendships
has_many :inverse_friendships, :class_name => 'Friendship',
:foreign_key => 'friend_id'
has_many :inverse_friends, :through => :inverse_friendships, :source => :user
end
Users controller (the User itself is created by Devise)
class UsersController < ApplicationController
before_action :authenticate_user!
def show
#user = User.find(params[:id])
end
def my_friends
#friendships = current_user.friends
end
def search
#users = User.search(params[:search_param])
if #users
#users = current_user.except_current_user(#users)
render partial: 'friends/lookup'
else
render status: :not_found, nothing: true
end
end
private
def require_same_user
if current_user != set_user
flash[:alert] = "Restricted."
redirect_to root_path
end
end
def set_user
#user = User.find(params[:id])
end
end
Friendship model:
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: 'User'
has_many :shipments
end
Friendships controller:
class FriendshipsController < ApplicationController
def index
#friendships = Friendship.all
end
def create
#friendship = current_user.friendships.build(:friend_id => params[:friend_id])
if #friendship.save
flash[:success] = "Added to friends."
redirect_to my_friends_path
else
flash[:alert] = "Impossible to add as a friend."
redirect_to my_friends_path
end
end
def destroy
#friendship = current_user.friendships.find_by(friend_id: params[:id])
#friendship.destroy
flash[:notice] = "Unfriended."
redirect_to my_friends_path
end
private
def name
#name = friend_id.name
end
end
Schema:
create_table "friendships", force: :cascade do |t|
t.integer "user_id"
t.integer "friend_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "shipments", force: :cascade do |t|
t.string "name"
t.integer "length"
t.integer "width"
t.text "adress"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "height"
t.integer "kg"
end
add_index "shipments", ["user_id"], name: "index_shipments_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.string "name"
t.integer "phone", limit: 30
t.string "username"
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
Shipment form view (new):
<%= form_for(shipment, html: { multipart: true }) do |f| %>
<p>Choose a friend from your friendlist or fill the address field manually:</p>
<%= f.select :friend_id, user.friendships.map{ |friendship|
[friendship.friend.name, friendship.id] } %>
<%= f.text_field :adress, placeholder: "Address and index" %>
<%= f.submit "Submit", class: "button" %>
<% end %>
With ActiveRecord::Base, you could use eager loading and nested form to solve your problem.
Eager load the object related to the main object and use nested form to display the related object.

Unsure if association is working in my rails app

My app has users and users are able to post links to my app. I have an association set up so that a user has many :links and links belong_to a user (see below for models). Now I am trying to get the users email to appear in the show template and I am getting a nil value for Link.user for new links. Can someone maybe shed some light as to why? Is my association incorrect? The user has been logged in when posting links.
User model:
class User < ActiveRecord::Base
has_many :links
acts_as_voter
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Link model:
class Link < ActiveRecord::Base
belongs_to :user
acts_as_votable
attr_accessor :avatar
mount_uploader :avatar, AvatarUploader
end
show.html.erb:
<%= time_ago_in_words(#link.created_at) %> by <%= #link.user.try(:email) %>
Schema:
create_table "links", force: :cascade do |t|
t.string "title"
t.string "url"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "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.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
Link creation in Links controller;
def new
#link = Link.new
end
def create
#link = Link.new(link_params)
if #link.save
redirect_to root_path
else
render 'new'
end
end
private
def link_params
params.require(:link).permit(:title, :url, :avatar)
end
Make sure the links are actually being assigned to a user when created.
Using the rails console. Try looping through the links and making sure they have user_ids:
in the rails console:
ap Link.all.map(&:user)
If they are indeed owned by a user
<%= #link.user.email %>
should print out the email.
You should be able to do something like this in your controller:
#user.links << params[:new_link]
Make sure that much is working.
You are using devise. Inside your Link controller, you have to authenticate your logged on user.
# app/controllers/links_controller.rb
before_action :authenticate_user!
def create
#link = current_user.links.new(link_params)
if #link.save
redirect_to root_path
else
render 'new' # generally this is a render 'edit'
end
end
I truncated the file here. Please read the devise manual

undefined method `firstname' for nil:NilClass Rails4

Can somebody help me with this error? I add profile controller by console without model. Database it's working fine. I am sure that i have lastname and firstname in seed.rb and i just did db:setup/migration.
Here's the show.html
.page-header
.h1
=link_to #user.firstname + " " + #user.lastname, edit_user_registration_path
Database:
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 "firstname"
t.string "lastname"
t.string "username"
t.boolean "admin", default: false
user.rb
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 :reviews
has_many :products
validates_presence_of :firstname, :lastname
end
Profile controler:
class ProfileController < ApplicationController
def show
#user = User.find_by_username(params[:id])
if #user
#reviews=#user.reviews.order(:created_at).reverse_order.limit(5)
render action: :show
end
end
end
This part
#user = User.find_by_username(params[:id])
returns nil, because you pass id from params as a username to find_by_username finder. In can't find the username (string) which is id (integer).
It should be
#user = User.find(params[:id])
Take a look at docs on how finders work
If you are using find_by_username then you should pass params[:username] instead of params[:id] .
Also this part:
if #user
#reviews=#user.reviews.order(:created_at).reverse_order.limit(5)
render action: :show
end
even if the if statement is false, render action: :show will still be called - it's the default.
if you defined a method that said nothing:
def test
end
rails would call: render action: :name_of_method
You need to use a redirect and unless:
redirect_to users_url, notice: 'user not found' unless #user
Good luck!

Pass Account id (parent) to User (child) with Devise in Rails

I have set up the necessary models and views to have a Devise resource, Account and User. Account has_many users & User belongs_to account. The schema reflects account_id as an attribute of user. I'm probably mistaken but I was under the impression that this account_id attribute would automatically be filled when an Account is logged in & creates a new user. Upon checking the Rails console, it seems all new users created this way had a nil value for account_id. Separate question but is this the ideal way to have multitenancy in an application using Devise?
Models:
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :account, :inverse_of => :users
accepts_nested_attributes_for :account
end
account.rb
class Account < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :users, :inverse_of => :account, :dependent => :destroy
accepts_nested_attributes_for :users
has_many :projects
end
schema.rb (just users & accounts)
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.integer "account_id"
t.boolean "supervisor"
t.string "name"
end
create_table "accounts", 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 "name"
end
users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
def new
#user = User.new
end
def create
#user.skip_confirmation! # confirm immediately--don't require email confirmation
if #user.save
flash[:success] = "User added and activated."
redirect_to users_path # list of all users
else
render 'new'
end
end
def index
#users = User.all
end
end
accounts_controller.rb
class AccountsController < ApplicationController
def new
#accounts = Account.new
#accounts.users.build
end
def create
#account = Account.new(params[:account])
if #account.save
flash[:success] = "Account created"
redirect_to accounts_path
else
render 'new'
end
end
end
from registrations > edit.html.erb
<% if account_signed_in? %>
<div class="jumbotron">
<span><%= link_to "Add user", new_user_registration_path, class: "btn btn-primary btn-sm" %></span>
</div>
<% end %>
I am not sure what how exactly you are trying to create a user
But creating a user with
#account.users.build
would automatically add account_id to user object.
Hope this helps! :)

how to get user who creates role in ruby on rails

I want to get user info like usernaem or first name who create roles in my ROR application. There are many to many association between users and roles by having role_users as join table. I am able to crate roles and save them. But i have no idea how to get user who creates role. For example,if I am Admin, I can create new roles in application. While creating role, I need to get user who is creating that role in roles_controller.rb.
roles_controller.rb
class RolesController < ApplicationController
before_filter :authorize_admin!
def index
#roles = Role.all
end
def new
#role = Role.new
end
def create
#role = Role.new(params[:role])
# #article.user_id = current_user.id
#role_user.user_id = current_user.id
if #role.save
flash[:success] = "role created!"
redirect_to roles_path(#role)
else
render 'new'
end
end
def show
#role = Role.find(params[:id])
end
def edit
#role = Role.find(params[:id])
end
def update
#role = Role.find(params[:id])
if #role.update_attributes(params[:role])
flash.notice = "Role #{#role.name} has been updated"
redirect_to role_path(#role)
else
render 'edit'
end
end
def destroy
#role = Role.find(params[:id])
#role.destroy
redirect_to action: 'index'
end
end
users_controller.rb
class Admin::UsersController < Admin::BaseController
before_filter :find_user, :only => [:show, :edit, :update, :destroy]
def index
#users = User.all( :order => :email )
#roles = Role.all
end
def show
end
def new
#user = User.new
end
def create
is_admin = params[:user].delete(:is_admin) == "1"
#user = User.new(params[:user])
#user.save
#user_role = RoleUser.new({:user_id => #user.id, :role_id => params[:role_id]})
#user_role.role_id = params[:role_id]
#user_role.save
#user.is_admin = is_admin
if #user.save
flash[:notice] = "User has been created."
redirect_to admin_users_path
else
flash[:alert] = "User has not been created."
render :action => :new
end
end
def edit
end
def update
if params[:user][:password].empty?
params[:user].delete(:password)
end
set_admin
if #user.update_attributes(params[:user])
flash[:notice] = "User has been updated."
redirect_to admin_users_path
else
flash[:alert] = "User has not been updated."
render :action => :new
end
end
def destroy
if #user == current_user
flash[:alert] = "You cannot delete yourself!"
else
#user.destroy
flash[:notice] = "User has been deleted."
end
redirect_to admin_users_path
end
private
def find_user
#user = User.find(params[:id])
end
def set_admin
is_admin = params[:user].delete(:is_admin) == "1"
#user.is_admin = true
end
end
user.rb
class User < ActiveRecord::Base
has_many :roles, through: :role_users
has_many :role_users
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :password, :password_confirmation,
:remember_me, :first_name, :last_name, :is_admin, :contact_no, :birth_date,
:joining_date, :is_active, :is_hr, :is_manager, :user_code, :designation
# attr_accessible :title, :body
end
role_user.rb
class RoleUser < ActiveRecord::Base
belongs_to :user
belongs_to :role
attr_accessible :role_id, :user_id
end
role.rb
class Role < ActiveRecord::Base
attr_accessible :name
has_many :users, through: :role_users
has_many :role_users
end
ActiveRecord::Schema.define(:version => 20130601093644) do
create_table "role_users", :force => true do |t|
t.integer "role_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "roles", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
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
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 "is_admin"
t.string "username"
t.string "first_name"
t.string "last_name"
t.string "contact_no"
t.date "birth_date"
t.boolean "is_active"
t.date "joining_date"
t.string "avatar_url"
t.boolean "is_hr"
t.boolean "is_manager"
t.string "designation"
t.string "user_code"
t.string "user_role"
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
Pass user_id as a params via the form:
#_form.html.haml
%input{:name => "user_id, :value => current_user.id, :type => "hidden"}
#controller:
creating_user = User.find(params[:role][:user_id])
But I don't think I'm following you completely. Is this what you're after?
If you want to get user object from.role just do #role.user. it will execute sql query which will join all 3 tables and return you a user
As per my understanding you need to add one more column into roles model i.e user_id. Make proper association between them like. User can have many roles and role belongs to User.
While creating a new role you need to pass the user_id also or use association for this will save you from passing explicitly user_id value.
ex:-
#current_user.roles.new(params[:new_role])
when you will role_user object you can fetch role owner data with proper association between there models i.e User, Role, RoleUser.
ex:-
#role_user.role.user

Resources