Rails Nested Resource Routes - ruby-on-rails

I'm fairly new to rails and I don't think I'm understanding the routing completely. When I try to access the edit action I get the following error:
ActiveRecord::RecordNotFound in StoreController#show
Couldn't find Gear with id=edit
Rails.root: /Users/dave/rails_projects/outdoor
Application Trace | Framework Trace | Full Trace
app/controllers/store_controller.rb:7:in `show'
Request
Parameters:
{"user_id"=>"104",
"id"=>"edit"}
Show session dump
Show env dump
Response
Headers:
None
Here is my view with the link that is throwing this error:
<li><%= link_to "Store Appearance", edit_user_store_path(#user) %></li>
Here is my nested route:
resources :users do
resources :store
end
Here is my controller
class StoreController < ApplicationController
def index
#store = current_user.gears.paginate(page: params[:page])
end
def show
#gears = Gear.find(params[:id]).user.gears.paginate(page: params[:page])
end
def edit
end
def update
end
end
Model Store
class Store < ActiveRecord::Base
attr_accessible :storeimage, :storename
belongs_to :user
validates :user_id, :presence => true
end
Model User
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :userimage, :remove_userimage
has_secure_password
has_many :gears
has_many :comments, :dependent => :destroy
has_one :store, :dependent => :destroy
before_save :create_remember_token
require 'carrierwave/orm/activerecord'
mount_uploader :userimage, UserpicUploader
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :first_name, presence: true,
length: {:maximum => 50 }
validates :last_name, presence: true,
length: {:maximum => 50 }
validates :email, presence: true,
format: {:with => email_regex},
uniqueness: {:case_sensitive => false}
validates :password, presence: true,
confirmation: true,
length: {within: 6..40}
include Tire::Model::Search
include Tire::Model::Callbacks
def name
first_name + " " + last_name
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Please help.

You need to pass both the user_id and id params in the URL when you're accessing a store object nested under a user, so your URL should look like this:
/users/1/stores/3/edit
Versus:
/users/1/stores/edit
You also need to pass both of those as arguments to your path helper, ie:
edit_user_store_path(#user, #store)

Related

ActiveModel::MissingAttributeError in RequestsController#create, can't write unknown attribute `request_id'

I'm getting an error regarding saving a request for a job on a website I'm making. Basically the user (candidate) will make a request for a job through the job/show.html.erb page, the comment will then display on the show.html.erb page with any other candidates who have also applied for the job. When the user types their name in the text box and submits it I get the error mentioned above. After looking online it seems the problem lies in my realtionships in the Models. Any ideas?
RequestsController
class RequestsController < ApplicationController
before_action :authorise
#set_request, only: [:show, :edit, :update, :destroy]
def create
#job = Job.find params[:job_id]
#request = #job.requests.new(request_params) <- Error highlights this line
#request.candidate_id = #current_candidate.id #sets the user_id FK
#request.save #saves the #comment
# object to the comments table
respond_to do |format|
format.html{redirect_to #job}
end
end
private
def request_params
#This is the method ehich whitelists the data fields from the format
params.require(:request).permit(:content, :job_id, :candidate_id)
end
end
Request Model
class Request < ActiveRecord::Base
belongs_to :job, dependent: :destroy
has_many :candidates
end
Candidate Model
class Candidate < ActiveRecord::Base
has_secure_password
validates_uniqueness_of:can_email
belongs_to :request
validates :can_name, presence: true
validates :can_surname, presence: true
validates :college, presence: true
validates :can_email, presence: true
validates :address, presence: true
validates :experience, presence: true
validates :password_digest, presence: true
validates :college_year, numericality: { only_integer: true }
end
Job Model
class Job < ActiveRecord::Base
belongs_to :sector
has_many :requests, dependent: :destroy
validates :name, presence: true
validates :employer, presence: true
validates :sector, presence: true
validates :experience_req, presence: true
validates :job_info, presence: true
end
assuming that in your routes.rb file you have the following routes defined:
resources :jobs do
resources :requests
end
which nests the routes, (see http://guides.rubyonrails.org/routing.html#nested-resources)
It is completely unnecessary to pass in job_id in, via the requests part of the params. i.e. You don't need to include it as an input in your form because the url already passes the param in.
look at your server output the params hitting your 'create` action should look something like this:
params = { job_id: 1, request: {content: "hello world", candidate_id: "123"}}
in that case you permit the following:
def request_params
params.require(:request).permit(:content, :candidate_id)
end
and the first two lines of create will be correct:
#job = Job.find(params[:job_id])
#request = #job.requests.new(request_params)

Strong parameters in Ruby

I'm getting the error message about strong parameters. I think it's just that rails 4 doesn't use attributes anymore. the code for my toy.rb is:
class Toy < ActiveRecord::Base
attr_accessible :name, :price, :vendor
validates :name, :presence => true
validates :price, :presence => true
validates :price, :numericality => true
validates :vendor, :presence => true
end
how can I change this to strong parameters?
EDIT: I used a different rb i changed it to employees and this is what I have:
class Employee < ActiveRecord::Base
params.require(:employee).permit(:first, :last, :salary, :salary, :ssn)
validates :first, :presence => true
validates :last, :presence => true
validates :salary, :presence => true
validates :salary, :numericality => true
validates :ssn, :presence => true
end
It's still telling me "ndefined local variable or method `params' for #"
The code you need is
params.require(:toy).permit(:name, :price, :vendor)
You will put this in your controller. Typically, you create a private method:
def create
Toy.create(toy_params)
end
private
def toy_params
params.require(:toy).permit(:name, :price, :vendor)
end
See http://guides.rubyonrails.org/getting_started.html#saving-data-in-the-controller for more information.
Edit
I think I might have misled you with my original answer. The code goes in the controller, not the model.
Strong params are designed to help your controller send specific data to your model. It's meant to protect your app against unauthorized data being passed:
#app/controllers/toys_controller.rb
Class ToysController < ActiveRecord::Base
def new
#toy = Toy.new #-> creates a blank AR object
end
def create
#toy = Toy.new(toys_params) #->creates new AR object (populating with strong params)
#toy.save
end
private
def toys_params
params.require(:toys).permit(:your, :params, :here)
end
end

ActiveModel::MassAssignmentSecurity::Error even when using accepts_nested_attributes_for

My complete error message is:
ActiveModel::MassAssignmentSecurity::Error in
WorkoutsController#create Can't mass-assign protected attributes:
workout_entry
The params that I am sending looks like:
{"workout"=>{"unit"=>"kg", "name"=>"2013-02-20T21:26:19", "note"=>nil, "workout_entry"=> [{"workout_entry_number"=>"1", "exercise_id"=>2, "entry_detail"=>[{"set_number"=>"1", "weight"=>"32", "reps"=>"43"}]}]}}
I have a workout that has many workout entries and each workout entries can have many entry details. The note is optional.
workout.rb
class Workout < ActiveRecord::Base
has_many :workout_entries, dependent: :destroy
attr_accessible :id, :name, :note, :unit, :workout_entries_attributes
belongs_to :user
accepts_nested_attributes_for :workout_entries
validates_presence_of :name
validates_presence_of :unit, :inclusion => %w(kg lb)
validates_associated :workout_entries
default_scope order("created_at DESC")
end
workout_entry.rb
class WorkoutEntry < ActiveRecord::Base
belongs_to :workout
belongs_to :exercise
has_many :entry_details, dependent: :destroy
attr_accessible :workout_id, :exercise_id, :workout_entry_number, :entry_details_attributes
accepts_nested_attributes_for :entry_details
validates :exercise_id, presence: true, numericality: {only_integer: true}, :inclusion => { :in => 1..790 }
validates :workout_id, presence: true, numericality: {only_integer: true, greater_than_or_equal_to: 1}
validates :workout_entry_number, presence: true, numericality: {only_integer: true, greater_than_or_equal_to: 1}
end
workouts_controller.rb
class WorkoutsController < ApplicationController
respond_to :json
before_filter :authenticate_user!
def index
respond_with(current_user.workouts)
end
def show
respond_with(current_user.workouts.find(params[:id]))
end
def create
respond_with(current_user.workouts.create(params[:workout]))
end
def update
#workout = current_user.workouts.find(params[:id])
if #workout.update_attributes(params[:workout])
render json: #workout, status: :ok
else
render json: #workout.errors, status: :unprocessable_entity
end
end
def destroy
respond_with(current_user.workouts.destroy(params[:id]))
end
end
I tried switching the ordering of attr_accessible and accepts_nested_attributes_for within the workout.rb, but it does not work.
I even tried to set
config.active_record.whitelist_attributes = true
but creating was still prevented.
accepts_nested_attributes_for does not add any attributes to the whitelist. Whatever keys your trying to pass to update_attributes have to be listed in attr_accessible, in your case you need to add workout_entry to attr_accessible.
It does look like you have an error in the form, if your using fields_for then it should be using the key workout_entries_attributes, which you have accessible.
Try to add workout_entry_ids in attr accessible in your workout model.
I decided to not use accepts_nested_attributes_for in the workout and workout_entry models because it wasn't working for me. I also updated the format of my json that is sent. Details are in the link below
link

Elasticsearch, Tire & Associations

Running: Ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0], Rails 3.2.0
I'm trying to get elastic search working through the TIRE gem across associations. For some reason I keep getting the following error/errors when performing a rake on a TIRE import or occasionally on a view:
Daves-MacBook-Pro:outdoor dave$ rake environment tire:import CLASS=Gear FORCE=true
[IMPORT] Deleting index 'gears'
[IMPORT] Creating index 'gears' with mapping:
{"gear":{"properties":{}}}
[IMPORT] Starting import for the 'Gear' class
--------------------------------------------------------------------------------
101/101 | 100% rake aborted!######################################
undefined method `last_name' for nil:NilClass
Tasks: TOP => tire:import
Here are my models:
GEAR
class Gear < ActiveRecord::Base
attr_accessible :title, :size, :price, :image_url, :sub_category_id, :user_id
belongs_to :user
belongs_to :sub_category
validates :title, presence: true
validates :size, presence: true
validates :price, presence: true
validates :sub_category_id, presence: true
validates :user_id, presence: true
include Tire::Model::Search
include Tire::Model::Callbacks
def self.search(params)
tire.search(load: true, page: params[:page], per_page: 18) do
query { string params[:query]} if params[:query].present?
end
end
def to_indexed_json
to_json(methods: [:sub_category_name, :user_last_name, :user_first_name, :user_email])
end
def sub_category_name
sub_category.name
end
def user_first_name
user.first_name
end
def user_last_name
user.last_name
end
def user_email
user.email
end
end
USER
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation
has_secure_password
has_many :gears
before_save :create_remember_token
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :first_name, presence: true,
length: {:maximum => 50 }
validates :last_name, presence: true,
length: {:maximum => 50 }
validates :email, presence: true,
format: {:with => email_regex},
uniqueness: {:case_sensitive => false}
validates :password, presence: true,
confirmation: true,
length: {within: 6..40}
def name
first_name + " " + last_name
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Sub_Category
class SubCategory < ActiveRecord::Base
attr_accessible :name
belongs_to :category
has_many :gears
end
What am I missing? Thanks.
I had a few NIL values in my database that was the reason for the errors. Hopefully this can save a few people some time.

Rails - Submitting Nested Values That Already Exist

I have a model, Tran that has a foreign key to the User model. In the view for creation a Tran (transaction), I have a dropdown that allows the user to select the User that started the transaction. When I post this transaction, the record is set with the correct user ID:
Then, in my Trans model I added "belongs_to", as I understand I should do this for foreign keys:
class Tran < ActiveRecord::Base
belongs_to :buying_user, :class_name => 'User'
Now, when my client passes up the params in the post, my Tran.new craps out because I am passing up a userID and not a full record. Is the
#trans_controller.rb
def create
#title = "Create Transaction"
#bombs on this call
#tran = Tran.new(params[:tran])
How am I supposed to handle this?
Update as requested:
tran.rb
class Tran < ActiveRecord::Base
has_many :transaction_users, :dependent => :destroy, :class_name => 'TransactionUser'
belongs_to :submitting_user, :class_name => 'User'
belongs_to :buying_user, :class_name => 'User'
accepts_nested_attributes_for :transaction_users, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
validates :description, :presence => true,
:length => {:maximum => 100 }
validates :total, :presence => true
validates_numericality_of :total, :greater_than => 0
validates :submitting_user, :presence => true
validates :buying_user, :presence => true
validates_associated :transaction_users
end
user.rb
class User < ActiveRecord::Base
has_many :trans
attr_accessor :password
attr_accessible :firstname, :lastname, :email, :password, :password_confirmation
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :firstname, :presence => true,
:length => {:maximum => 50 }
validates :lastname, :presence => true,
:length => {:maximum => 50 }
validates :email, :presence => true,
:format => {:with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
# Register callback to before save so that we can call extra code like password encryption
before_save :encrypt_password
# Class methods
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
# Public methods
def has_password?(submitted_password)
self.encrypted_password == encrypt(submitted_password)
end
def full_name
"#{self.lastname}, #{self.firstname}"
end
def self.active_users
# TODO
#User.find_
User.all
end
private
def encrypt_password
self.salt = make_salt if new_record?
self.encrypted_password = encrypt(password)
end
def encrypt (string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
params hash on submit:
{"commit"=>"Submit",
"tran"=>{"total"=>"100",
"submitting_user"=>"1",
"description"=>"Description"},
"authenticity_token"=>"88qI+iqF92fo/M9rPfMs1CLpEXqFLGQXfj0c9krXXac=",
"utf8"=>"✓",
"user"=>"1"}
error:
User(#70040336455300) expected, got String(#70040382612480)
beginning of controller:
def create
#title = "Create Transaction"
#tran = Tran.new(params[:tran])
It crashes on the Tran.new line. Thanks so much!
Typically the User model would have has_many :transactions, :class_name => Tran
Then you would do this...
#user.transaction_create(params[:tran])
or
#user.build
it depends on what parameters are actually passed in params[:tran], but the idea is that the has_many side does the creating of the belongs_to.
I figured it out! The problem the whole time was that my db column name on my Trans table that linked to my Users table was submitting_user instead of submitting_user_id. Then, when I added the belongs_to association to submitting_user rails got confused and made that field a User, instead of an integer.

Resources