Which Active record association should I use - ruby-on-rails-5

I'm using rails 5.1.4 , so I have a table USER within I store all the users, then a user can send friend request to other users, and I want to store that request into other table named FRIEND, like user_1 ( who send the request) - user_2 (who is requested for) , but you will understand that those two user (user_1, user_2) are coming from USER table.
It means: first I have this table Users which contains all the users. And what I want to say is that any user in this table user can be friend with any other user from the same table user.

I'm not 100% certain what your asking in your question but it sounds like what you're looking to do is to have a table called Users and another table called Friends and to be able to store a value for the friend request. I believe what you want to look into is a "has_many :through association" using a "join table". Check out this video it walks you through it http://blog.teamtreehouse.com/what-is-a-has_many-through-association-in-ruby-on-rails-treehouse-quick-tip
here's more info on the Active Record association http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
EDIT:
Based on your below post what you want to do is just a simple has_many association. In your User model add has_many :friends, dependent: :destroy and in your Friend model add belongs_to :users now go to your routes file and make friends a nested route of user by doing
# nested routes for users
resources :users do
resources :friends
end
in your friends table make sure you add a foreign key for users lik ethis in the migration t.references :user, foreign_key: true
now in your friends_controller you need to update the actions like this. Replace the example "patent" with your "friend" object.
class PatentsController < ApplicationController
# first loads #user and then #patent for the below actions.
before_action :set_user, only: [:index, :show, :new, :edit, :create, :update]
before_action :set_patent, only: [:show, :edit, :update, :destroy]
# GET /patents
# GET /patents.json
def index
#patents = #user.patents
end
# GET /patents/1
# GET /patents/1.json
def show
end
# GET /patents/new
def new
#patent = #user.patents.new
end
# GET /patents/1/edit
def edit
end
# POST /patents
# POST /patents.json
def create
#patent = #user.patents.new(patent_params)
respond_to do |format|
if #patent.save
format.html { redirect_to user_patents_path(#patent.user), notice: 'Patent was successfully created.' }
format.json { render :show, status: :created, location: #patent }
else
format.html { render :new }
format.json { render json: #patent.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /patents/1
# PATCH/PUT /patents/1.json
def update
respond_to do |format|
if #patent.update(patent_params)
format.html { redirect_to user_patents_path(#patent.user), notice: 'Patent was successfully updated.' }
format.json { render :show, status: :ok, location: #patent }
else
format.html { render :edit }
format.json { render json: #patent.errors, status: :unprocessable_entity }
end
end
end
# DELETE /patents/1
# DELETE /patents/1.json
def destroy
#patent.destroy
respond_to do |format|
format.html { redirect_to user_url(#user), notice: 'Patent was successfully destroyed.' }
format.json { head :no_content }
end
end
#######################
# private methods
#######################
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:user_id])
end
def set_patent
#patent = Patent.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def patent_params
params.require(:patent).permit(:patent_title, :patent_office, :patent_number, :patent_status, :patent_date, :patent_description, :user_id)
end
end

Related

Can't mass-assign protected attributes: document

I have two models Employee and Documents which are as follows:
Employee.rb
class Employee < ActiveRecord::Base
has_one :document #,dependent: :destroy
attr_accessible :age, :dob, :empNo, :first_name, :gender, :last_name, :middle_name, :document_attributes
accepts_nested_attributes_for :document
validates :first_name, presence: true , length: { maximum: 50 }
validates :empNo, presence: true, uniqueness:{ case_sensitive: false }
validates_length_of :empNo, :minimum => 5, :maximum => 5
#before save { |user| user.email = email.downcase }
end
Document.rb
class Document < ActiveRecord::Base
belongs_to :employee,foreign_key: "empno"
attr_accessible :idate, :iedate, :insuranceno, :iqamano, :iqedate, :iqidate, :passportno, :pedate, :pidate, :vedate, :vidate, :visano
end
and the controller file is employees_controller.rb(I have only shown new,create,show funcs)
def show
#employee = Employee.find(params[:id])
#document=Document.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #employee }
end
end
# GET /employees/new
# GET /employees/new.json
def new
#employee = Employee.new
#document= Document.new
respond_to do |format|
format.html # new.html.erb
format.json { render :json=>{:employee=> #employee,:document=>#document}, status: :created, :location=>{:employee=> #employee,:document=>#document} }
end
end
# POST /employees
# POST /employees.json
def create
#employee = Employee.create!(params[:employee])
#document = Document.create!(params[:document])
respond_to do |format|
if #employee.save and #document.save
format.html { redirect_to #employee, notice: 'Employee was successfully created.' }
format.json { render :json=>{:employee=> #employee,:document=>#document}, status: :created, location: #employee }
else
format.html { render action: "new" }
format.json { render json: #employee.errors, status: :unprocessable_entity }
end
end
end
When I create a new employee I get the following error
ActiveModel::MassAssignmentSecurity::Error in EmployeesController#create
Can't mass-assign protected attributes: document
The requsts parameters are fine as seen below
{"utf8"=>"✓",
"authenticity_token"=>"vXSnbdi+wlAhR5p8xXvTWhi85+AVZgOZufClx73gc8Q=",
"employee"=>{"empNo"=>"11111",
"first_name"=>"Thaha",
"middle_name"=>"Muhammed",
"last_name"=>"Hashim",
"age"=>"25",
"gender"=>"M",
"dob(1i)"=>"2014",
"dob(2i)"=>"7",
"dob(3i)"=>"18",
"document"=>{"passportno"=>"bycucde63"}},
"commit"=>"Create Employee"}
I have gone through nearly all posts on stackoverflow dealing with this issue and mostly the issue is related to
not using attr_accessible
not using accepts_nested_attributes_for
not using :document_attributes
If I change the value of config.active_record.whitelist_attributes to false then the error goes away(There is a warning in developer log about the same) and both the models are created but only attributes of employee model is filled with passed values wheras the attributes of document model is nil.
EDIT #1
If I tried to add :document to attr_accessible then I get the following error
ActiveRecord::AssociationTypeMismatch in EmployeesController#create
What is that I am doing wrong here?
Understanding Mass Assignment
Mass Assignment is the name Rails gives to the act of constructing your object with a parameters hash. It is "mass assignment" in that you are assigning multiple values to attributes via a single assignment operator.
The following snippets perform mass assignment of the name and topic attribute of the Post model:
Post.new(:name => "John", :topic => "Something")
Post.create(:name => "John", :topic => "Something")
Post.update_attributes(:name => "John", :topic => "Something")
In order for this to work, your model must allow mass assignments for each attribute in the hash you're passing in.
There are two situations in which this will fail:
You have an attr_accessible declaration which does not include :name
You have an attr_protected which does include :name
It recently became the default that attributes had to be manually white-listed via a attr_accessible in order for mass assignment to succeed. Prior to this, the default was for attributes to be assignable unless they were explicitly black-listed attr_protected or any other attribute was white-listed with attr_acessible.
The easiest way here would be, i suppose, to add :document to attr_accessible.
If an attribute is not listed there, ActiveRecord will not allow you to "mass-assign" them.
Relating to my comment, you'd end up with something like this:
...
"dob(3i)"=>"18",
"document"=><#Document ...>}, # {"passportno"=>"bycucde63"} is just a Hash, not a Document, that's why it raises "ActiveRecord::AssociationTypeMismatch"
"commit"=>"Create Employee"}
In the code, like:
def create
#document = Document.create!(params[:document])
#employee = Employee.create!(params[:employee].merge(:document => #document))

Ruby on rails with paperclip

I am a new programmer on ruby on rails, and i have problem when upload picture. Deos anyone can help me. thanks in advance.
class StudentsController < ApplicationController
before_action :set_student, only: [:show, :edit, :update, :destroy]
# GET /students
# GET /students.json
def index
#students = Student.all
end
# GET /students/1
# GET /students/1.json
def show
end
# GET /students/new
def new
#student = Student.new
end
# GET /students/1/edit
def edit
end
# POST /students
# POST /students.json
def create
#student = Student.create(student_params)
respond_to do |format|
if #student.save
format.html { redirect_to #student, notice: 'Student was successfully created.' }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
private
#def student_params
#params.require(:student).permit(:image_file)
#end
# PATCH/PUT /students/1
# PATCH/PUT /students/1.json
def update
respond_to do |format|
if #student.update(student_params)
format.html { redirect_to #student, notice: 'Student was successfully updated.' }
format.json { render :show, status: :ok, location: #student }
else
format.html { render :edit }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
# DELETE /students/1
# DELETE /students/1.json
def destroy
#student.destroy
respond_to do |format|
format.html { redirect_to students_url, notice: 'Student was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_student
#student = Student.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def student_params
params.require(:student).permit(:name, :gender, :telephone, :address)#, :image_file
end
end
Can't really find a problem in your post. It's a bit hard to understand. Did you follow the docs on https://github.com/thoughtbot/paperclip? I take it your file attachment is in the Student model?
params.require(:student).permit(:name, :gender, :telephone, :address)#, :image_file
now you only permit to save name, gender, telephone and address, the image file wil not be saved. You still have to permit it.

Creating a Friend While On Their Profile Page

I want a User(x) to be able to add another User(y) as a friend while User(x) is on User(y's) Profile Page. I set up a has_many_through and everything works except that I can only add a friend from the User Index View. Thank you in advance...The code is below:
Also:
I wanted to place the "friend" link on the view/profile/show.html.erb. When I added #users = User.all to the existing profiles_controller.rb I received the error - undefined method friendships' for nil:NilClass. When I replaced #user = User.find(params[:id]) with #users = User.all I received the error - NoMethodError in Profiles#show... undefined methodinverse_friends' for nil:NilClass
The Code that works in UserIndexView but not ProfileShowView:
% for user in #users %>
<div class="user">
<p>
<strong><%=h user.email %> <%= user.id %></strong>
<%= link_to "Add Friend", friendships_path(:friend_id => user), :method => :post%>
<div class="clear"></div>
</p>
</div>
<% end %>
The following error occurs:
NoMethodError in Profiles#show
Showing /Users/mgoff1/LOAP_1.2.2/app/views/profiles/show.html.erb where line #13 raised:
undefined method `each' for nil:NilClass
Extracted source (around line #13):
10:
11:
12:
13: <% for user in #users %>
14: <div class="user">
15: <p>
16: <strong><%=h user.email %> <%= user.id %></strong>
. . .
app/views/profiles/show.html.erb: 13:in`_app_views_profiles_show_html_erb___2905846706508390660_2152968520'
app/controllers/profiles_controller.rb:19:in `show'
The code to the rest is below.
friendship.rb
class Friendship < ActiveRecord::Base
attr_accessible :create, :destroy, :friend_id, :user_id
belongs_to :user
belongs_to :friend, :class_name => "User"
end
user.rb
class User < ActiveRecord::Base
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
# 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 :email, :password, :password_confirmation, :remember_me, :profile_attributes
# attr_accessible :title, :body
has_one :profile
accepts_nested_attributes_for :profile
before_save do | user |
user.profile = Profile.new unless user.profile
end
end
friendships_controller.rb
class FriendshipsController < ApplicationController
def create
#friendship = current_user.friendships.build(:friend_id => params[:friend_id])
if #friendship.save
flash[:notice] = "Added friend."
redirect_to current_user.profile
else
flash[:error] = "Unable to add friend."
redirect_to root_url
end
end
def destroy
#friendship = current_user.friendships.find(params[:id])
#friendship.destroy
flash[:notice] = "Removed friendship."
redirect_to current_user.profile
end
end
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def index
#users = User.all
end
end
profiles_controller.rb
class ProfilesController < ApplicationController
# GET /profiles
# GET /profiles.json
def index
#profiles = Profile.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #profiles }
end
end
# GET /profiles/1
# GET /profiles/1.json
def show
#user = User.find(params[:id])
#profile = Profile.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #profile }
end
end
# GET /profiles/new
# GET /profiles/new.json
def new
#profile = Profile.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #profile }
end
end
# GET /profiles/1/edit
def edit
#user = User.find(params[:id])
#profile = Profile.find(params[:id])
end
# POST /profiles
# POST /profiles.json
def create
#profile = Profile.new(params[:profile])
respond_to do |format|
if #profile.save
format.html { redirect_to #profile, notice: 'Profile was successfully created.' }
format.json { render json: #profile, status: :created, location: #profile }
else
format.html { render action: "new" }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# PUT /profiles/1
# PUT /profiles/1.json
def update
#profile = Profile.find(params[:id])
respond_to do |format|
if #profile.update_attributes(params[:profile])
format.html { redirect_to #profile, notice: 'Profile was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# DELETE /profiles/1
# DELETE /profiles/1.json
def destroy
#profile = Profile.find(params[:id])
#profile.destroy
respond_to do |format|
format.html { redirect_to profiles_url }
format.json { head :no_content }
end
end
end
routes.rb
BaseApp::Application.routes.draw do
resources :friendships
resources :profiles
#get "users/show"
devise_for :users, :controllers => { :registrations => "registrations" }
resources :users
match '/show', to: 'profile#show'
match '/signup', to: 'users#new'
root to: 'static_pages#home'
match '/', to: 'static_pages#home'
. . .
You aren't setting #users in ProfilesController#show.
for object in collection just calls collection.each do |object|, which is why you're getting undefined method 'each' for NilClass (and also why it's generally discouraged to use that syntax, as it creates confusing errors like this one).
profiles_controller.rb
def show
#users = User.all
#...
end
Anytime you try to call methods with no actual object you'll get the 'method undefined'.
It means that the method IS defined - but you have a 'nil' and are trying to call it on that and that method doesn't exists for the 'nil' object.
Please check your actual users table. You'll need users to work with. Please verify that you have some.
If necessary you can create users (at the script/rails console) with
User.new(:name=>'fred', :password =>'pword', :password_confirmation => 'pword' )
You can also place this in your db/seeds.db file so you can run rake db:seed the first time you set the application up on a new machine.

How can I manage public records and user specific records

I have a situation where a company is managed by a user. i.e.: A user can create, read, update and delete their own companies. But I'd also like that same user to access a list of all companies in the system, even when logged out.
e.g.:
user_a manages the following companies: company_a and company_b
user_b manages the following companies: company_c and company_d
user_a should be able to see a list of his own companies (a and b) as well as a list of all companies (a, b, c, and d)
What's the best way to handle this in the controllers?
Idealy, I'd like to have it setup under 2 separate routes as follows:
/companies
/users/1/companies
Should I have one controller for companies, or multiple? and how would that work?
I'm looking for best practices in this type of scenario.
In your situation approach can be:
Use Devise RubyGem to handle authentication. https://github.com/plataformatec/devise
Create or Scaffold simple CompaniesController with RESTful actions set: index, new, create, edit, udpate, destroy actions.
Add before_filter in CompaniesController to restrict access to action which require user authentication:
before_filter :authenticate_user!, :except => [:public_list]
You should have has_many assosiation between User and Company ActiveRecord models, to access companies collection of current_user.
Here goes example code:
Routing:
resources :users do
resources :companies
end
match '/companies' => 'companies#public_list', :as => :public_companies_list
Controller:
class CompaniesController < ApplicationController
before_filter :authenticate_user!, :except => [:public_list]
def index
#companies = current_user.companies
end
def show
#company = current_user.companies.find(params[:id])
end
def new
#company = current_user.companies.new
end
def edit
#company = current_user.companies.find(params[:id])
end
def create
#company = current_user.companies.new(params[:company])
respond_to do |format|
if #company.save
format.html { redirect_to #company, notice: 'Company was successfully created.' }
else
format.html { render action: "new" }
end
end
end
def update
#company = current_user.companies.find(params[:id])
respond_to do |format|
if #company.update_attributes(params[:company])
format.html { redirect_to #company, notice: 'Company was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
def destroy
#company = current_user.companies.find(params[:id])
#company.destroy
respond_to do |format|
format.html { redirect_to companies_url }
end
end
end
For public companies list add this method:
def public_list
#companies = Company.all
end
IMHO if all user can see all companies it's perfect to have one controller to get this job. Just in template you can check if current user is author of specified company and then add link to edit this company etc. if you want of course.

NoMethodError in LineItemsController#create

I'm working with the Agile Web Development with Rails (4th edition) book and I bumped into a piece of code that is not working. I tried hard to figure out why it's not working, but I didn't make it.
BACKGROUD INFORMATION
The following classes are involved:
class Cart < ActiveRecord::Base
has_many :line_items, :dependent => :destroy
end
class LineItem < ActiveRecord::Base
belongs_to :product
belongs_to :cart
end
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
end
end
NOW
here is where it fails:
class LineItemsController < ApplicationController
def index
#line_items = LineItem.all`
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #line_items }
end
end
# GET /line_items/1
# GET /line_items/1.xml
def show
#line_item = LineItem.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #line_item }
end
end
# GET /line_items/new
# GET /line_items/new.xml
def new
#line_item = LineItem.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #line_item }
end
end
# GET /line_items/1/edit
def edit
#line_item = LineItem.find(params[:id])
end
# POST /line_items
# POST /line_items.xml
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = **#cart.line_items.build(:product => product)**`
ERROR MESSAGE
*NoMethodError in LineItemsController#create
undefined method `line_items' for 9:Fixnum
Rails.root: /home/tmiskiew/depot*
*app/controllers/line_items_controller.rb:53:in `create'
Request
Parameters:
{"product_id"=>"4",
"authenticity_token"=>"dR4nL5zI+R7qIIPwNkl3EoaI1KyFWRokvh92m3PwD8o="}*
Anyone an idea what's wrong with #cart.line_items.build?
I'm working rails 3.0.9 and ruby 1.8.7
Thanks
Thomas
Have a look at your error
undefined method line_items' for 9:Fixnum
This says that #cart is a number, not an Cart object (#cart = current_cart from create action returns a number),
current_cart function returns a number because
Cart.find(session[:cart_id]) returns recordNotFound and your rescue block from current_cart function will be executed.
Remember that every function in Ruby returns the result of the last executed line, so you will get returned the cart.id
Edit: For first comment, try to rewrite method
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart # this will get returned
end
end
Here's how I fixed it...hope it works for you too.
/app/models/cart.rb:
def add_product(product_id)
current_item = line_items.find_by_product_id(product_id)
if current_item
current_item.quantity += 1
else
current_item = line_items.build(:product_id => product_id)
end
return current_item
end
Add the return in. I'm not 100% sure why this was failing, but I think the function only returns the quantity, rather than a line item unless the if statement evaluates to true.
I have similar error, it turns out I have a typo in Cart.rb:
class Cart < ActiveRecord::Base
has_many :line_items, :dependent => :destroy
end
typo in :destory... and it cause the undefined method... hope this help.
I was having the same problem, and I felt really stuck on it.
I fixed it by rollbacking the database and migrating it again.
Commands on terminal:
rake db:rollback
rake db:migrate