rails getting value from view to conroller - ruby-on-rails

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]

Related

Rails: File to Upload does not get passed from Form to the controller

This is the Form. All of the fields get passed (and saved) except the one containing the File.
I have checked that using the
render plain: params[:article].inspect method
giving out this (I have entered the value "n" for all fields):
{"country"=>"n", "region"=>"n", "town"=>"n", "street"=>"n", "company"=>"n", "title"=>"n", "content"=>"n"}
I am leaving out superfluous fields here to make the Form shorter:
<%= form_for(#article, html: { multipart: true }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :country %>
<%= f.text_field :country, :required => true,
placeholder: "enter country" %>
</div>
<%= f.label :content %>
<%= f.text_field :content, :required => true, placeholder: "town..." %>
</div>
</div>
</div>
</div>
<span class="picture">
<%= form_for #article, html: { multipart: true } do |f| %>
<%= f.text_field :title %>
<%= fields_for :pictures do |ff| %>
<%= ff.file_field :picture %>
<% end %>
<% end %>
</div>
I have also tried the slight variation here, but no change
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
The create method at the Controller is like this:
def create
#article = current_user.articles.build(article_params)
if #article.save
flash[:success] = "Article created!"
redirect_to root_url
else
render 'articles/new'
end
end
and yes, the new method in the Articles controller, is like I was indicated by peers here:
def new
#article = current_user.articles.build
#article.pictures.build
end
The Article Model
class Article < ActiveRecord::Base
belongs_to :user
has_many :pictures
accepts_nested_attributes_for :pictures, allow_destroy: true
And the pictures Model
class Picture < ActiveRecord::Base
belongs_to :article
mount_uploader :picture, PictureUploader
end
Change your <%= fields_for :pictures do |ff| %> to <%= f.fields_for :pictures do |ff| %>

Rails 4 trouble with accepts_nested_attributes_for

I am new to rails and I'm trying the accepts_nested_attributes_for function. I am creating an inventory system and the accepts_nested_attributes_for feature is being used to attach multiple order details to an order. An order must also be associated with store location.
The problem I'm having is the order is being created but no data is being passed to the order details table.
My views are below:
Orders View
<h1>Place An Order</h1>
<%= form_for ([#location, #order]) do |f| %>
<p>
<%= f.label :customer_id %><br />
<%= f.text_field :customer_id %>
</p>
<p>
<h3>Items</h3>
<%= f.fields_for :order_details do |builder| %>
<%= render 'order_detail_fields', :f => builder %>
<% end %>
</p>
<p><%= link_to_add_fields "Add Item", f, :order_details %></p>
<p>
<%= f.submit %>
</p>
<% end %>
Order_details_fields Partial
<p class="fields">
<%= f.label :item_id %><br />
<%= f.text_field :item_id %></br>
<%= f.label :quantity %></br>
<%= f.text_field :quantity %></br>
<%= f.label :cost %></br>
<%= f.text_field :cost %></br>
<%= f.label :discount %><br />
<%= f.text_field :discount %><br />
<%= f.hidden_field :_destroy %>
<%= link_to_function "remove", "remove_fields(this)" %>
</p>
Orders Controller
class OrdersController < ApplicationController
def index
#orders = Order.all
end
def show
#order = Order.find(params[:id])
end
def new
#order = Order.new
#location = Location.find(params[:location_id])
end
def create
#location = Location.find(params[:location_id])
#order = #location.orders.create(order_params)
##order = #order.order_details.create
if #order.save
redirect_to #order
else
render :action => 'new'
end
end
private
def order_params
params.require(:order).permit(:customer_id, order_detials_attributes: [:id, :item_id, :quantity, :cost, :discount])
end
end
Orders Model
class Order < ActiveRecord::Base
belongs_to :location
has_many :order_details, :dependent => :destroy
accepts_nested_attributes_for :order_details, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
Order Details Model
class OrderDetail < ActiveRecord::Base
belongs_to :order
end
Routes
resources :locations do
resources :orders
end
resources :orders do
resources :order_details
end
Any help with this would be greatly appreciated
Build
Looks like everything is right to me - the only problem being the issue #Pavan outlined, which is that when you use accepts_nested_attributes_for, you have to build the associative object, so it can be used in the form:
#app/controllers/orders_controller.rb
Class OrdersController < ApplicationController
def new
#location = Location.find parmas[:id]
#order = Order.find params[:id]
#order.order_details.build
end
end
Although this looks like the only issue you have, there may be other problems (validation on the OrderDetail model as an example (which you don't have)
The only issue with what both I and Pavan have recommended is if you don't build your associative data, the fields_for don't show on the form. If your fields are showing, it may be a different issue, which will be highlighted in the params hash

undefined method `[]' for nil:NilClass error in 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.

How to Pass an array from form to controller?

I have been following Brandon Tilley's instructions on creating a private message system and want to modify the way the recipient of a private message is passed (from check-box to text-box).
In the view I have this:
<%= f.label :to %><br />
<%= f.text_field :to, placeholder: "Recip...(separated by commas)" %>
How can I accept input as a text input that passes an array of integers to the controller?
Extra Details:
Full View:
<h1>New Conversation</h1>
<%= form_for(#conversation) do |f| %>
<div>
<%= f.label :to %><br />
<%= f.text_field :to, placeholder: "Recip...(separated by commas)" %>
</div>
<br />
<%= f.fields_for :conversation do |c| %>
<div>
<%= c.label :subject %>
<%= c.text_field :subject %>
</div>
<%= c.fields_for :messages do |m| %>
<div>
<%= m.label :body %><br />
<%= m.text_area :body %>
</div>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
Within the controller I have this:
def create
redirect_to users_path unless current_user
#conversation = UserConversation.new(params[:user_conversation])
#conversation.user = current_user
#conversation.conversation.messages.first.user = current_user
...
Within the model I have this:
accepts_nested_attributes_for :conversation
delegate :subject, :to => :conversation
delegate :users, :to => :conversation
attr_accessor :to
*before_create :create_user_conversations*
private
def create_user_conversations
return if to.blank?
to.each do |recip|
UserConversation.create :user_id => recip, :conversation => conversation
end
end
end
Edit: New Model:
def to
to.map(&:user_id).join(", ") *stack too deep error*
end
def to=(user_ids)
#to = user_ids.split(",").map do |recip|
UserConversation.create :user_id => recip.strip, :conversation => conversation
end
rails helpers are not set up to handle arbitrary array input auto-magically.
you can use multiple checkboxes or parse your text input which is a commaa separated list of user names. In your model
def to=(string)
#to = User.where(:name => string.split(',')).select(:id).map(&:id)
end
for a nicer user experience you can use tagsinput jquery plugin and/or autocomplete.
also note that if you use a form to modify this same object, you need to regenerate the comma separated string as :value option for the text_field input to correctly prepopulate your edit form.
<%= text_field_tag "user_conversation[to]", (#conversation.to || []).join(',') %>
In the view:
<%= f.label :to %><br />
<%= f.text_field :to, placeholder: "Recip...(separated by commas)" %>
In the model:
attr_accessible :to
attr_accessor :to
before_create :create_user_conversations
private
to.split(",").each do |recip|
UserConversation.create :user_id => recip, :conversation => conversation
end

Creating forms for Multiple Nested Resources in Rails 3

I have been following Ryan Bates' tutorial on nested forms Railscast 196
The form for the new action shows the nested attributes for quizzes but does not show nested attributes for the key. I am guessing this is because quizzes have a has_many relationship where key has a has_one relationship... But I cannot figure out what I'm doing wrong?
Any help is much appreciated!
This is my model:
class Repository < ActiveRecord::Base
has_many :quizzes, :dependent => :destroy
has_one :key, :dependent => :destroy
accepts_nested_attributes_for :key, :quizzes
end
This is my controller:
def new
#repository = Repository.new
3.times { #repository.quizzes.build }
#repository.key = Key.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #repository }
end
end
This is my view:
<div class="field">
<%= f.label :wp_uid %><br />
<%= f.text_field :wp_uid %>
<% f.fields_for :quizzes do |quiz_fields| %>
<p>
<%= quiz_fields.label :name, "Name" %><br />
<%= quiz_fields.text_field :name %>
</p>
<% end %>
<% f.fields_for :key do |key_fields| %>
<div class="field">
<%= key_fields.label :value, "Value" %><br />
<%= key_fields.text_field :value %>
</div>
<div class="field">
<%= key_fields.label :expiry, "Expiry" %><br />
<%= key_fields.date_select :expiry %>
</div>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You should try modifying your fields_for blocks to use <%= %>
Try changing to:
<%= f.fields_for :key do |key_fields| %>
The railscast could have been made before the change in Rails 3 to use <%= %> instead of <%%>.
Ryan has a nested_form gem that you may find useful for this as well. I haven't tried using it yet, but plan to next time I start a new project.
https://github.com/ryanb/nested_form
Try building the key object as
#reposity.build_key
From the rails docmentation
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Unsaved+objects+and+associations
If you wish to assign an object to a has_one association without saving it, use the build_association method. The object being replaced will still be saved to update its foreign key.

Resources