I am trying to do the following:
<%= order.user.try(:first_name) %>
<%= order.user.try(:last_name) %>
<%= order.user.try(:email) %>
This works however when I view the index of this page, the data does not appear in the table. I also viewed the logs and saw that the relevant data is being posted
Started POST "/orders" for 127.0.0.1 at 2013-02-18 11:15:02 +0000
Processing by OrdersController#create as HTML Parameters:
{"utf8"=>"?",
"authenticity_token"=>"Rjf7+Z8UAPh9ZofIrOs+p6AoGPfgd/6rfdTRqJLtx0g=",
"user"=>{"first_name"=>"Test", "last_name"=>"TestHome",
"email"=>"test#test.com"}, "order"=>{"address"=>"3433234243",
"card_number"=>"45423554213994", "card_type"=>"visa",
"card_expires_on(1i)"=>"2013", "card_expires_on(2i)"=>"2",
"card_expires_on(3i)"=>"1"}, "commit"=>"Confirm Order"} Cart Load
(0.0ms) SELECT carts.* FROM carts WHERE carts.id = 8 LIMIT 1
so I alternatively tried to do
<%= order.user.first_name %>
<%= order.user.last_name %>
<%= order.user.email %>
Doing this resulted in
NoMethodError in Orders#index
Showing C:/Users/sites/e-smart/app/views/orders/index.html.erb where line #18 raised:
undefined method `first_name' for nil:NilClass
I understand that the result of this error is because first_name is empty.
What is the best way to get the data.
Order.rb
class Order < ActiveRecord::Base
attr_accessible :address, :card_expires_on, :card_type, :ip_address, :card_number, :first_mame, :last_name, :email, :quantity
belongs_to :cart
has_many :line_items, :dependent => :destroy
belongs_to :user
User.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
has_many :role_users
has_many :orders
You are saying:
I understand that the result of this error is because first_name is empty.
This is not correct. The cause of the error is that user is nil. This is also in line with the behavior or try() to return -blank-.
Make sure you have an order with the user populated correctly. This means your order table must have a user_id and the user must be assigned correctly.
You're comparing two different things here - the try is working correctly in your view, it's returning nil when you call it on nil (undefined method 'first_name' for nil:NilClass is because order.user is nil, not because first_name is nil.
This is unrelated to your POST - what is the actual issue you're trying to solve here?
Let me clarify the meaning of this error first.
NoMethodError in Orders#index
Showing C:/Users/sites/e-smart/app/views/orders/index.html.erb where line #18 raised:
undefined method `first_name' for nil:NilClass
The above error doesn't mean that first_name for user is empty, but the user object itself is nil. It means that, your #order.user is nil and not #order.user.first_name is empty.
So, order.user.try(:first_name) should be read as print the first_name of the user who placed this order if there is an user associated with the order, otherwise do nothing but don't throw any error
The parameters in the form are being sent properly to your controller and may be you are missing something in the controller that associates the order and user records. Look into the controller action that is saving the object and make sure you are associating order and user properly.
Hope this helps
Related
I need to access the fields_for nested attribute but I keep getting this error:
undefined method '[]' for nil:NilClass
For line:
braintree_account_params[:braintree_subscription_attributes][0][:plan_token]
I have tried:
params[:braintree_subscription_attributes][0][:plan_token]
params["braintree_subscription_attributes"][0]["plan_token"]
braintree_account_params[:braintree_subscription_attributes][0][:plan_token]
braintree_account_params["braintree_subscription_attributes"][0]["plan_token"]
params[:braintree_subscription_attributes]['0'][:plan_token]
params["braintree_subscription_attributes"]['0']["plan_token"]
braintree_account_params[:braintree_subscription_attributes]['0'][:plan_token]
braintree_account_params["braintree_subscription_attributes"]['0']["plan_token"]
None have worked
This:
params[:braintree_account][:braintree_subscription_attributes].first[:plan_token]
Error: Undefined method first # for ActionController
My params:
Parameters: {"utf8"=>"✓", "braintree_account"=>{"first_name"=>"asfd", "last_name"=>"asfd", "braintree_subscription_attributes"=>{"plan_token"=>"4zfr"}}, "user_id"=>"1"}
Strong Params:
params.require(:braintree_account).permit(..., braintree_subscription_attributes: [:id, :plan_token])
Models:
class BraintreeAccount < ApplicationRecord
has_one :braintree_subscription
accepts_nested_attributes_for :braintree_subscription
end
class BraintreeSubscription < ApplicationRecord
belongs_to :braintree_account
end
How can I access plan_token?
Because this is a has one, and not a has many, you won't have more than 1 nested object in your attributes. The array syntax is only necessary if there is expected to be more than 1 child.
braintree_account_params[:braintree_subscription_attributes][:plan_token]
I’m using Rails 5. I have this model
class ConfidentialMemo < ApplicationRecord
belongs_to :scenario
belongs_to :scenario_role
end
In my view, I have this drop down set up for selecting a field to be populated into the “scneairo_role” field …
<%= f.collection_select :scenario_role, #scenario.roles, :id, :name, include_blank: false %>
In the create method of my controller, I have this
#confidential_memo = ConfidentialMemo.new(confidential_memo_params)
…
private
def confidential_memo_params
params.require(:confidential_memo).permit(:description, :scenario_id, :scenario_role)
end
but I’m getting the error
ScenarioRole(#70207639353420) expected, got String(#70207645188180)
What does this error mean and more importantly, what do I need to adjust tis save my model successfully?
Change :scenario_role to :scenario_role_id in your collection_select method and in your controller params method. Your form is outputting and sending an id (in the form of a string), but if you just try to assign an id to #note.scenario_role, it'll fail with the same type of message.
I am having problems display an attribute in a belongs_to relationship. Lease belongs_to Unit. Unit has a column "number" in the db. When I try to display this attribute on the lease show page, it gives me an error of undefined method `number' for nil:NilClass. I feel like I'm doing something stupid and over looking it.
lease.rb
belongs_to :unit
unit.rb
has_many :leases
leases_controller.rb
def show
#lease = Lease.find(params[:id])
end
views/leases/show.html.erb
<%= #lease.unit.number %>
If I change my show page code to #lease.unit_id it will show the id of the unit. Here is a pic of my data base showing the Unit_id.
Your model may have unit_id attribute, but how about units that does not have that record with id = 1 have You checked?
Quick (dirty) fix:
<%= #lease.unit.number unless #lease.unit.nil? %>
you have to validate the Unit ID's presence on Lease model
validates :unit, presence: true
so your Lease model wouldn't be saved to database unless you've set the unit_id to Lease instance
now you may delete your existing Unit records from database, and start again.
you may need to add more integrity of each data, please read this
update
ok how about if "DBAs deleting records under some circumstancies" ?
you can delegate to Unit#number to Lease instance
delegate :number, to: :unit, prefix: true
now you can access the lease.unit.number even when the unit_id is nil, you can access it using lease.unit_number
I've watched the RailsCast, another nested attributes video, lots of SO posts, and fought with this for a while, but I still can't figure it out. I hope it's something tiny.
I have two models, User (created by Devise), and Locker (aka, a product wishlist), and I'm trying to create a Locker for a User when they sign up. My login form has a field for the name of their new Locker (aptly called :name) that I'm trying to assign to the locker that gets created upon new user registration. All I'm ever greeted with is:
WARNING: Can't mass-assign protected attributes: locker
I've tried every combination of accepts_nested_attributes and attr_accesible in both of my models, yet still nothing works. I can see from the logs that it's being processed by the Devise#create method, and I know Devise isn't smart enough to create my models how I want :)
Here's the relevant bits of my two models:
# user.rb
class User < ActiveRecord::Base
attr_accessible :username, :email, :password, :password_confirmation, :remember_me, :locker_attributes
# Associations
has_many :lockers
has_many :lockups, :through => :lockers
# Model nesting access
accepts_nested_attributes_for :lockers
end
and
# locker.rb
class Locker < ActiveRecord::Base
belongs_to :user
has_many :lockups
has_many :products, :through => :lockups
attr_accessible :name, :description
end
# lockers_controller.rb (create)
#locker = current_user.lockers.build(params[:locker])
#locker.save
I'm assuming I need to override Devise's create method to somehow get this to work, but I'm quite new to rails and am getting used to the black box "magic" nature of it all.
If anyone can help me out, I'd be incredibly thankful. Already spent too much time on this as it is :)
EDIT: I realized I omitted something in my problem. My Locker model has three attributes - name, description (not mandatory), and user_id to link it back to the User. My signup form only requires the name, so I'm not looping through all the attributes in my nested form. Could that have something to do with my issue too?
EDIT 2: I also figured out how to override Devise's RegistrationsController#create method, I just don't know what to put there. Devise's whole resource thing doesn't make sense to me, and browsing their source code for the RegistrationsController didn't help me much either.
And for bonus points: When a user submits the login form with invalid data, the Locker field always comes back blank, while the regular Devise fields, username & email, are filled in. Could this also be fixed easily? If so, how?
first, you have a typo :
attr_accessible :locker_attributes
should be plural :
attr_accessible :lockers_attributes
then, the standard way to use nested_attributes is :
<%= form_for #user do |f| %>
<%# fields_for will iterate over all user.lockers and
build fields for each one of them using the block below,
with html name attributes like user[lockers_attributes][0][name].
it will also generate a hidden field user[lockers_attributes][0][id]
if the locker is already persisted, which allows nested_attributes
to know if the locker already exists of if it must create a new one
%>
<% f.fields_for :lockers do |locker_fields| %>
<%= locker_fields.label :name %>
<%= locker_fields.text_field :name %>
<% end %>
<% end %>
and in you controller :
def new
#user = User.new
#user.lockers.build
end
def create
# no need to use build here : params[:user] contains a
# :lockers_attributes key, which has an array of lockers attributes as value ;
# it gets assigned to the user using user.lockers_attributes=,
# a method created by nested_attributes
#user = User.new( params[:user] )
end
as a side note, you can avoid building a new locker for new users in controller in different ways:
create a factory method on User, or override new, or use an after_initialize callback to ensure every new user instantiated gets a locker builded automatically
pass a specific object to fields_for :
<% f.fields_for :lockers, f.object.lockers.new do |new_locker_fields| %>
Someone helped me figure out the solution in a more "Rails 4'y" way with strong attributes & how to override Devise's sign_up_params (to catch all the data coming from my signup form).
def sign_up_params
params.require(:user).permit(:username, :email, :password, :lockers_attributes)
end
Gemfile addition: gem 'strong_parameters'
Commenting out the attr_accessible statement in my user.rb file, since apparently strong parameters eliminate the need for attr_accessible declarations.
# attr_accessible :username, :email, :password, :password_confirmation, :lockers
And the/a correct way of building a Locker before submitting the form: at the beginning of the nested form:
<%= l.input :name, :required => true, label: "Locker name", :placeholder => "Name your first locker" %>
Thanks again for all your help. I know a question like this is difficult to answer without seeing the whole codebase.
i have table AuditLog with fields including: audited_id | audited_type
That results in data like:
108 | Photo
303 | Comment
What I want to do is create a link to the item, so for the example above:
here is the photo
I'm trying to use a polymorphic_path but am getting an error: "undefined method `model_name' for Fixnum:Class"
When using:
<%= link_to 'Here she is', polymorphic_path([audited_id, audited_type]) %>
Ideas? Thanks
Updating with code based on the answer by Luke below:
class NewsFeed < ActiveRecord::Base
default_scope :order => 'news_feeds.created_at DESC'
belongs_to :feeded, :polymorphic => true
end
class Note < ActiveRecord::Base
has_many :newsfeed, :as => :feeded
end
In the partial which is being passed the local storyitem:
<%= link_to 'Here she is', polymorphic_path(storyitem.feeded) %>
The DB migration file, contains the following line for CreateNewsFeeds
t.references :feeded, :polymorphic => true
You should have a method #auditable (or whatever your polymorphic association is called) on AuditLog objects. If you pass the result of that method to polymorphic_path it will return the correct path for you.
Update:
Assuming you have the following associations (or are using acts_as_auditable or something that sets up the relationships for you):
class AuditLog
belongs_to :auditable, :polymorphic => true
end
class AuditedObject
has_many :audits, :as => :auditable
end
You'll be able to call auditable on any instance of AuditLog, and it will return the associated audited object. So you can call
<%= link_to 'Here she is', polymorphic_path(audit_log.auditable) %>
to get a link to the audited object.
So, anywhere that you have a polymorphic association in a class, there is an instance method setup with the name of that association that will return the associated object.
Gosh, I'm hoping that makes sense. Let me know if you need me to clarify it further.
The problem with polymorphic_path it needs an object, so you first need to fetch the object from the database.
Depending on your use case this can be a big performance problem.
In case of a log viewer, where you have a list of for example 100 entries,
and just want to show links to the entires, you will fetch 100 objects, just to get their path.
I had a similar problem, my solution was to hack a method to construct the path from the class name and id:
class AuditLog
...
def audited_path
"/#{self.audited_type.tableize}/#{self.audited_id}"
end
The method will return for example "/photos/302". But of course it will work only for quite simple routings.