undefined method `[]' for nil:NilClass error in rails - ruby-on-rails

I have 2 conotrollers and 3 models:
Models:
problem.rb
class Problem < ActiveRecord::Base
has_many :problemtags
has_many :tags, :through => :problemtags
end
tag.rb
class Tag < ActiveRecord::Base
validate :name, :presence => true
has_many :problemtags
has_many :problems, :through => :problemtags
end
problemtag.rb
class Problemtag < ActiveRecord::Base
belongs_to :problem
belongs_to :tag
end
problems_controller.rb
class ProblemsController < ApplicationController
def new
#all_tags = Tag.all
#new_problem = #problem.problemtags.build
end
def create
params[:tags][:id].each do |tag|
if !tag.empty?
#problem.problemtags.build(:tag_id => tag)
end
end
end
def problem_params
params.require(:problem).permit(:reporter_id, :status, :date_time, :trace_code)
end
tags_controller.rb
//tags_controller is generate with scaffold
And I have below code in problems view:
new.html.erb
<%= fields_for(#new_problem) do |f| %>
<div class="field">
<%= f.label "All Tags" %><br>
<%= collection_select(:tags, :id, #all_tags, :id, {}, {:multiple => true}) %>
</div>
<% end %>
when I run the project, the problem's view is show, but when I complete the textfields and select tags and then click on submit button, I get below error:
NoMethodError in ProblemsController#create
undefined method `[]' for nil:NilClass
Extracted source (around line #22):
#problem = #reporter.problems.build(problem_params)
params[:tags][:id].each do |tag|
if !tag.empty?
#problem.problemtags.build(:tag_id => tag)
end
I do not understand the problem. any one can describe the problem to me?

As stated by your answers, your issue is that you're not sending the right data to your controller (and consequently params[:tags] will be blank):
Form
You're firstly missing the form_builder object in your collection_select (so your tags will likely not be sent inside the correct params hash). Although this may be by design, you need to ensure you're passing the data properly:
<%= fields_for(#new_problem) do |f| %>
<div class="field">
<%= f.label "All Tags" %><br>
<%= f.collection_select(:tags, :id, #all_tags, :id, {}, {:multiple => true}) %>
</div>
<% end %>
Params
Secondly, we cannot see your form or params hash. This is vital, as your form needs to look like this:
<%= form_for #variable do |f| %>
<%= f.text_field :value_1 %>
<%= f.text_field :value_2 %>
<% end %>
This creates a params hash like this:
params { "variable" => { "name" => "Acme", "phone" => "12345", "address" => { "postcode" => "12345", "city" => "Carrot City" }}}
This will be the core reason why your controller will return the [] for nil:NilClass error - you'll be referencing params which don't exist. You'll need to call params[:variable][:tags] as an example
If you post back your params hash, it will be a big help

You could try using validate :tag_id, :presence => true to check for presence of the needed params.

I found 2 problems in my code:
in new.index.html(in problem view), the submit button is in the form_for and I write the field_for outside the form_for and when I click on submit button, the params hash of tags didn't create.
In collection_select, I forgot to add the name parameter of tag.
Correct new.html.erb code:
<%= form_for #problem do |f| %>
status: <%= f.text_field :status %><br/>
datetime: <%= f.datetime_select :date_time %><br/>
trace code: <%= f.text_field :trace_code %><br/>
<%= fields_for(#new_problem) do |f| %>
<div class="field">
<%= f.label "All Tags" %><br>
<%= collection_select(:tags, :id, #all_tags, :id,:name, {}, {:multiple => true}) %>
</div>
<% end %>
<%= f.submit %>
<% end %>
Thanks for all of the answers.

Related

How can I update two User objects in the same Rails form_for?

I'm trying to use a form_for in rails to update two objects from the User model at the same time. The reason is that a person can update basic information for both themselves and their spouse (two different users), without having to fill out two separate forms.
My current code for updating one user looks like this:
<%= form_for(#user, :url=> wizard_path, :method => :put) do |f| %>
<div class="form-group form-question-group">
<%= f.label :state, "What state do you live in?", class: "form-question" %>
<%= f.select(:state, options_for_select(us_states, selected: #user.state), {:prompt => "State"}, :class => "form-control", :required => true) %>
<%= f.hidden_field :user_id, value: #user.id %>
</div>
<div class="form-buttons">
<%= link_to "Back", previous_wizard_path, :class => "align-left" %>
<%= f.submit "Continue", :class => "btn btn-primary align-right" %>
</div>
<% end %>
How can I edit this form so that on submit it updates not just the current user, but also the user's spouse (which can be accessed by #user.spouse).
my idea is using your user controller update method
def update
if #user.update_attributes(user_params)
# here you update spouse
spouse = #user.spouse
if spouse.present?
spouse.state = #user.state
spouse.save
end
flash[:success] = 'success'
end
end
This sounds like the classic use case for ActiveRecord::NestedAttributes.
Nested attributes allow you to save attributes on associated records
through the parent. By default nested attribute updating is turned off
and you can enable it using the accepts_nested_attributes_for class
method. When you enable nested attributes an attribute writer is
defined on the model.
class User
belongs_to :spouse
accepts_nested_attributes_for :spouse
end
<%= form_for(#user, :url=> wizard_path, :method => :put) do |f| %>
# ...
<%= f.fields_for :spouse do |sf| %>
<%= sf.label :name, 'Your spouses name' %>
<%= sf.text_field :name %>
<% end %
<% end %>
def user_params
params.require(:user)
.permit(:foo, :bar, :baz, spouse_attributes: [:id, :name, :email]) # ...
end
Since this is handled on the model layer you don't have to do anything in your controller besides whitelisting the nested attributes.

HABTM association dropdown select

I am trying to create a dropdown select on a form. I have a HABTM association between professors and classrooms:
Classroom Model:
class Classroom < ApplicationRecord
has_and_belongs_to_many :professors
end
Professor Model:
class Professor < ApplicationRecord
has_and_belongs_to_many :classrooms
end
Strong Params:
def classroom_params
params.require(:classroom).permit(:name, :professor_ids => [])
end
I am trying to find a way to use f.select instead of select_tag inside the form. But when I do it, the database does not save the values. This way works:
<%= form_for #classroom do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<% array = Professor.all.map { |professor| [professor.user.name, professor.id] } %>
<%= select_tag "classroom[professor_ids][]", options_for_select(array) %>
<% end %>
But I am trying like that and it is not working:
<%= form_for #classroom do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<% array = Professor.all.map { |professor| [professor.user.name, professor.id] } %>
<%= f.select :professor_ids, options_for_select(array) %>
<% end %>
The view works correctly but when I submit the form, the value doesn't go to to the classroom_params. I tried to debug it stopping the controller after the submit and I got this:
The params came correctly with all the information submitted, but the classroom_params came missing the professor_ids.
Is there a way to do this dropdown using f.select?
You whitelisted the array of 'professor_ids', but your 'select' input returns 1 string ("prefessor_ids" => "2" from you screenshot). Maybe you want to set the select as 'multiple'? (I have not tested it, but i think params will be whitelisted correctly after that)
<%= form_for #classroom do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<%= s.collection_select :professor_ids, Professor.all, :id, :name, multiple: true %>
<% end %>
where
class Professor
...
delegate :name, to: :user
end
Update
You probably don't have 'cfg' variable in your controller action.

rails getting value from view to conroller

Having an issue getting a value from a form to the controller. I am using rails 4.0.
My view looks like this (new.html.erb)
<h1> POST A NEW LISTING </h>
<% if current_user.nil? %>
<h2>You must be logged in to view this page </h2>
<% else %>
<%= form_for [#user, #listing] do |f| %>
<%= f.label :title, 'Title' %> <br />
<%= f.text_field :title %>
<%= f.label :general_info, 'General Information' %> <br />
<%= f.text_area :general_info %>
<%= f.label :included, 'Included' %> <br />
<%= f.text_field :included %>
<%= f.label :length, 'Length' %> <br />
<%= f.text_field :length %>
<%= f.label :price, 'Price' %> <br />
<%= f.text_field :price %>
<%= fields_for #tagging do |u| %>
<%= u.label :tag, 'Tag' %> <br />
<%= u.text_field :tag %>
<% end %>
<%= f.submit "submit" %>
<% end %>
<% end %>
I am trying to add tags. I have 2 models to handle the tags:
models -> tag.rb
class Tag < ActiveRecord::Base
has_many :taggings
has_many :listings, through: :taggings
end
models -> tagging.rb
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :listing
end
tags keep track of the tag names themselves, while taggings keeps track of the connection to the listings.
When a user submits the form they will type in a string tag such as: "exampletag". I then need to search my tag model to get the tag_id of that specific tag. If it exists I need to put the tag_id and listing_id into taggings. Currently I have the listing_id correct, but I am having a problem even accessing the :tag symbol from the form.
This is what I have so far. Not that currently :tag_id is hardcoded in because I cant get #current_tag to return the information I need.
listings_conroller.rb #create
def create
#user = User.find(current_user.id)
#listing = #user.listings.build(listing_params)
#save before we get the listing ID
if #listing.save
#current_tag = Tag.where(:name => params[:tag])
#taggings = Tagging.new(:tag_id => 1, :listing_id => #listing.id)
if #taggings.save
flash[:success] = "Success"
redirect_to root_path
else
render :action => 'new'
end
else
render :action => 'new'
end
end
I thought that #current_tag = Tag.where(:name => params[:tag]) would return the correct listing but it seems to be returning null when I submit the form with a name which is in the database.
got it!
Since tags is nested under taggings I needed to access the param as:
params[:tagging][:tag]
instead of params[:tag]

rails accept nested atributes for a polymorphic association

I have an error "Can't mass-assign protected attributes: Upload", but I have assigned it to be accessible.
This is a nested form with a polymorphic association.
Models
class Upload < ActiveRecord::Base
attr_accessible :link, :post_id
belongs_to :uploadable, polymorphic: true
end
class Post < ActiveRecord::Base
attr_accessible :description, :title, :uploads_attributes
has_many :uploads, as: :uploadable
accepts_nested_attributes_for :uploads, :reject_if => lambda { |a| a[:content].blank?
}, :allow_destroy => true
end
I tried too put accept_nested ... for :uploadable but tells me dont exist the association
The action new on the controller is this one
def new
#post = Post.new
#post.uploads.new
end
and here is the form for create
<%= form_for [:admin,#post], remote: true, :html => {:multipart => true} do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title%>
</div>
<div class="field">
<%= f.label :description%><br />
<%= f.text_area :description %>
</div>
<div>
<%= f.fields_for :upload do |builder| %>
<%= render 'upload_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Upload", f, :uploads %>
</div>
<div class="actions">
<%= f.submit%>
</div>
<% end %>
The partial ...
<fieldset>
<%= f.label :file %><br />
<%= f.file_field :file %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
Dont think the javascript affects, so Im not going to put it here.
How I cna solve "Can't mass-assign protected attributes" on polymorphic asociations ?
Plz need help on this anyone. Cant belive I cant upload files, looks so simple on tutorials, and Its not working, or I get a Can't mass assign orthe upload its not saved ....
Try to use #post.uploads.build instead of #post.uploads.new
The associated model needs to know the identity of her parent to save the relationship.
I recommend you the following railscast: Polymorphic Association.
#uploads_controller.rb
before_filter :load_uploadable
def create
#upload = #uploadable.uploads.new(params[:upload])
....
end
private
def load_uploadable
resource, id = request.path.split('/')[1, 2] # /posts/1
#uploadable = resource.singularize.classify.constantize.find(id)
end
This line inside your view:
<%= f.fields_for :upload do |builder| %>
Should be this:
<%= f.fields_for :uploadable do |builder| %>
Because the association on the Post model is called "uploadable", not "upload".
For nested attributes to work, you will need to specify the model does accept nested attributes for this model, which can be done by putting this line underneath the belongs_to in your model:
accepts_nested_attributes_for :uploadable
And then you will need to make these attributes accessible, which you can do with this:
attr_accessible :uploadable_attributes

undefined method "_index_path" form_for problem

I'm trying to generate a form using the form_for helper in RoR but I am encountering what seems to be a routing error. Here are the relevant files:
models/equipment.rb
class Equipment < ActiveRecord::Base
attr_accessible :name, :tracking_number
validates :tracking_number, :presence => true,
:uniqueness => { :case_sensitive => true }
end
controllers/equipments_controllers.rb
class EquipmentsController < ApplicationController
def index
#equipments = Equipment.paginate(:page => params[:page])
end
def new
#equipment = Equipment.new
end
end
views/equipments/new.html.rb
<h1>Add an equipment</h1>
<%= form_for (#equipment) do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<div class="field">
<%= f.label :name %> <br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :tracking_number %><br />
<%= f.text_field :tracking_number %>
</div>
<%= f.submit "Add" %>
<% end %>
routes.rb
EquipmentTracking::Application.routes.draw do
root :to => "equipments#index"
resources :equipments
end
I don't see anything wrong but they output the following:
NoMethodError in Equipments#new
Showing /opt/ror/equipment_tracking/app/views/equipments/new.html.erb where line #2 raised:
undefined method `equipment_index_path' for #<#<Class:0xb6725a2c>:0xb6724640>
If I changed it to
<%= form_for (:equipment) do |f| %>
it seems to work ok. I'm also certain that the static variable #equipment is getting passed since
<%= #equipment %>
returns
#<Equipment:0xb685ece0>
I am at a loss here. I just did what I did while I was following the railstutorial.org book and I was able to finish the book.
I think your problem lies in your use of the word "equipments". If you open the Rails console run 'equipment'.pluralize you'll see that the plural of "equipment" is "equipment".
So I'd do a search through your project and replace any instance of "equipments" with "equipment" and I'd bet that would fix it.

Resources