Rails - add elements to array using text_field - ruby-on-rails

I want to do something that should be really simple: use an input text field to add elements to an array. As simple as it may seem, I'm kind of stuck...
Each User has a (single) Profile. Each Profile contains a text-field 'entertainment' that is serialized as an array in the ProfilesController.
I got as far as updating the attribute with a fixed text by using the following:
method in the ProfilesController
def update_entertainment
#user = User.find_by(params[:id])
#profile = #user.profile
#user.profile.update(entertainment: ["the usual suspects"])
redirect_to profile_path(current_user, tab:"entertainment")
end
profile_params in the ProfilesController
def profile_params
params.require(:profile).permit(:gender, :date_of_birth, :zip_code, :city, :state, :country, :marital_status, :entertainment )
end
the form
<div class="form-group">
<%= text_field :entertainment, :class => 'form-control' %>
<%= button_to("+", :action => :update_entertainment, :method => :put, :remote => true) %>
</div>
However, whatever I've tried (and that is a lot), I cannot manage to PUSH (not just update) the input of a text-field to the array. For now adding one element at a time will do. What I really want to do is give users the opportunity to ADD elements to the array.
I'm using Rails 4.0.x

The reason was in using button_to instead of usual form.
Normal form instead of button_to solved the problem.

SOLVED
With the help of #D.K. and #anushka I was able to solve the issue. I changed the changed the line
#profile.entertainment << params[:entertainment]
in the ProfilesController to
#profile.entertainment << params[:entertainment]
and changed the form to this:
<div class="form-group">
<%= form_tag(:action => :update_entertainment, :method=>'post', :multipart => true, :class => 'form-control') do %>
<div class="input-group">
<%= text_field_tag :entertainment, nil, :class => 'form-control form-group', :placeholder => 'add interests' %>
<span class="input-group-btn">
<%= submit_tag '+', class: 'btn btn-default' %>
</span>
</div>
<% end %>
</div>

Related

Whitelisted parameters do not appear in strong parameters

I have the following problem, I've tried to resolve it using Google, but it didn't give any noticeable results.
I have form for updating Model and I've been trying to add new parameters to strong parameters (model_params) and it seems like they are not including these params, event though their values appear in regular params (used byebug to check them out)
def model_params
params.require(:model).permit(
:id, # new param
:hidden_field_param, # also new one
# Long list of parameters omitted
nested_model_attributes: [:id, :file, :_destroy])
end
params
<ActionController::Parameters { All parameters including new and old ones } permitted: false>
model_params
<ActionController::Parameters { Only old ones } permitted: true>
Thank you.
UPD
_form.html.erb (partial)
<%= form_for #model, :remote => true, :authenticity_token => true, :html => { multipart: true } do |f| %>
<!-- All other fields omitted, they are working correctly -->
<div class="row">
<div class="col-xs-12">
<%= hidden_field_tag :hidden_field_param, 'Here is string value' %>
<% count = 0 %>
<%= f.fields_for :nested_model, method: :post, class: "" do |ff| %>
<%= ff.file_field :file, multiple: true, id: 'pictures_' + (count=count+1).to_s, class: "image_item" %>
<% end %>
</div>
</div>
<p>
<%= f.submit 'Done', class: 'btn btn-primary' %>
</p>
<% end %>
Notice that your hidden field tag is called as "hidden_field" and not "hidden_field_param". Also you don't need to mention :id while saving to database since it is auto-increment. Your model params should look like this:
def model_params
params.require(:model).permit(
:hidden_field,
# Long list of parameters omitted
nested_model_attributes: [:id, :file])
end

Rails form_for sending params to controller action and not model

In the controller review_queue I have a custom action that posts a result to a target URL, I want to build a form for this action. I am not going to save any of the fields to the DB I am just going to pass them in the params to the post_review action.
def post_review
RestClient::Request.execute(:method => :post,
:url => Rails.application.secrets['target_url'],
:content_type => :json,
:payload => #result_params.merge!(params[:reasons]).to_json,
:headers => HEADERS)
end
In the view I have a form that will be filled out and on submit it should send up the reasons when the form is submited, I am setting the review_queue_id and the status in the form, since these are static, but the reasons should come from the textarea
<%= form_for(:review_queue, url: { action: 'post_review', :review_queue_id => #review_queue.id, :status => 'accepted'} ) do |f| %>
<div class='form-group'>
<label for='comment'>Please give a reason? (required)</label>
<%= f.text_area(:reasons, placeholder: 'Your commentns ...', rows: 9, class: 'form-control') %>
</div>
<div class='modal-footer'>
<%= f.submit 'Approve', class: 'btn btn-success btn-decission btn-modal-left-side' %>
<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
</div>
<% end %>
error message:
NoMethodError - undefined method `reasons' for #<ReviewQueueApplication:0x007fa7ff7832d8>:
It seems as if rails is assuming the MVC architecture here, and assuming I want to pass the reasons to the review_queue model. there is no reasons column so it's dropping a no method error. Is there a way of specifying that the form is 'temporary' and only getting as far as the controller?
This seems like it should be a simple thing but there is some rails magic happening here.
NoMethodError - undefined method `reasons' for
ReviewQueueApplication:0x007fa7ff7832d8
form_for assumes that you are creating a form for a model object and expects the fields to be present in that specific model's table(in a normal situation).
You should be going with form_tag
<%= form_tag post_review_path, method: :get, :review_queue_id => #review_queue.id, :status => 'accepted'} ) do |f| %>
<div class='form-group'>
<label for='comment'>Please give a reason? (required)</label>
<%= text_area_tag(:reasons, placeholder: 'Your commentns ...', rows: 9, class: 'form-control') %>
</div>
<div class='modal-footer'>
<%= submit_tag 'Approve', class: 'btn btn-success btn-decission btn-modal-left-side' %>
<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
</div>
<% end %>
And in the controller access it like params[:reasons]. Also if you noticed, I've added method: :get to the form_tag as you don't want to save the info to DB
The rails helper form_for is used for forms for rails resources. You want to use the form_tag helper. Search for form_for and form_tag here for more information on these 2 methods.

How to construct a clickable link with a scope using Ransack and Rails

I have the requirement to have some scopes as clickable links in my application. This will allow the user to change the data they are seeing as required. Using Ransack and it's ransackable_scopes functionality I am very close. I do need to retain any filtering Ransack has done when the user clicks the scope.
I've got the scopes working but now I just need to construct the clickable link.
Here's my model:
class Product < ActiveRecord::Base
scope :upward_trending, -> { where( "status > ?", 100).where(above_revenue_average: true).order('end_date DESC') }
scope :downward_trending, -> { where( "status < ?", 100).order('end_date DESC') }
def self.ransackable_scopes(auth_object = nil)
[:upward_trending, :downward_trending]
end
end
Now in my view I've added these two scopes as hidden fields, like so:
<%= search_form_for #q, :html => {:class => 'filter-form'} do |f| %>
<div>
<%= f.hidden_field :upward_trending %>
<%= f.hidden_field :downward_trending %>
<%= f.label :name_cont, "Search", class: 'label' %>
<%= f.search_field :name_cont, class: 'form-control input-box', :placeholder => 'Search' %>
</div>
<div>
<%= f.submit "Filter", class: 'btn btn-primary' %>
<%= link_to "Clear Search", request.path, class:"btn btn-default" %>
</div>
<% end %>
From here I just need to create the links and it should work.. What is the best way to do this?
Thanks for your help!
I was planning to do dirty way. (But haven't yet)
create search_form_for every scope (you will have 2 form for your case)
set hidden field with own criteria (as you do in your code but each in own form)
make submit button looks like link (with css I think it is not very difficult. You can see Bootstrap button appeared as link)
Not very clean or elegant.
I achieved this by creating hidden fields for each scope and then creating a button with onclick javascript:
<%= f.hidden_field :upward_trending %>
<%= button_tag(:type => 'submit', :class => 'btn btn-primary scope-button upward_trending', :id => "upward_trending", :onclick => "document.getElementById('q_downward_trending').value = 0; document.getElementById('q_upward_trending').value = 1;") do %>
<i class="fa fa-chevron-up fa-2x"></i><br>Upward<br>Trending
<% end %>

Is it possible to make a link that functions as same as form does?

Now I have 2 forms that submit a comment.
Form Type A
<%=form_for(([#community, #comment]), :remote => true, :class => 'form' ) do |f| %>
<%= f.text_field :body, :id => "body", :class => "chat" %>
<button type="submit" class="btn">submit</button>
<% end %>
Form Type B
<%=form_for(([#user, #comment]), :remote => true, :class => 'form' ) do |f| %>
<%= f.text_field :body, :id => "body", :class => "chat" %>
<button type="submit" class="btn">submit</button>
<% end %>
Now, I want to have link_to button that functions as same as those forms do if a user clicks it.
When the user click on the link, #comment will be automatically filled just like below.
From Form Type A
#comment = "this is for community"
From Form Type B
#comment = "this is for user"
How can I do that? As far as I understand my situation.
Form is put type, then link_to is get type so it's impossible to re-use transaction of form.
Not sure what you mean by "transaction of form" but if you're asking if you can create/modify data via a single button or link than the answer is Yes, it is possible.
You can actually put with a link_to in rails ({:method => :put} (http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to)
If you want a button to do this you should checkout button_to (http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to)
It's better to use button_to.

Rails 2.3 search form loses field values on failed validation

I have a form that is a search form. When it fails to validate instead of retaining the field values, they are deleted and the user has to re-enter them. How can I retain the field values?
sign_in.html.erb:
<% form_tag( params.merge({ :action => "sign_in" }), :method => "post", :id => "sign_in_form" ) do %>
<div class="form_item_half">
<%= build_field_label(:user, :username, "Username") %>
<%= text_field :user, :username, :class => "text" %>
</div>
<div class="form_item_half" onKeypress="return keyRestricted(event)" onKeydown="return keyRestricted(event)">
<%= build_field_label(:user, :ssn_third, "Last four digits of Social Security Number") %>
<span id="exes">XXX-XX-</span>
<%= password_field :user, :ssn_third, :maxlength => "4", :class => 'text securitynum3', :autocomplete => "off" %>
</div>
<%= build_field_label(:user, :dob, 'Date of birth') %>
<div class="padding-bottom10 form_item_full clearfix date">
<%= select_month 14, :prompt => 'Select Month' %>
<%= text_field :dob, :day, :size => 2, :value => 'Day', :class => 'text' %>
<%= text_field :dob, :year, :size => 4, :value => 'Year', :class => 'text' %>
<div id="date_errors"></div>
</div>
<div class="padding-bottom10 form_item_full clearfix">
<%= render :partial => "/shared/captcha" %>
</div>
<div class="mp_buttons clearfix">
<input type="image" class="button" name="continue"
src="/images/v6/buttons/btn_signinsecurely.png" title="SignIn" alt="Sign In Securely">
</div>
<% end %>
onboarding_controller.rb:
def sign_in
if request.post?
flash[:errors] = Messages['onboarding/invalid_creds']; return unless #onboarding_user
flash[:errors] = Messages['onboarding/invalid_creds']; return unless params[:user][:username] == #onboarding_user.username
flash[:errors] = Messages['onboarding/invalid_creds']; return unless #onboarding_user.same_last_four?(params[:user][:ssn_third])
flash[:errors] = Messages['general/wrong_captcha']; return unless captcha_match?
unless
Date.new(params[:dob][:year].to_i, params[:date][:month].to_i, params[:dob][:day].to_i) == #onboarding_user.dob.to_date
flash[:errors] = Messages['onboarding/invalid_creds']
render :sign_in
end
session[:onboarding_user] = #onboarding_user
redirect_to :action => sign_up
end
end
If the entered values don't match what's stored in the database for #onboarding_user, then we flash an error message and render :sign_in. But this doesn't retain the field values...
#onboarding_user is loaded in a before_filter:
before_filter :load_objects_from_params, :only => :sign_in
def load_objects_from_params
#onboarding_user = OnboardingUser.find(params[:id]) unless params[:id].blank?
#onboarding_user = OnboardingUser.find_by_username(params[:user][:username]) unless #onboarding_user or request.get?
end
Here's the parameter hash seen by the controller:
Processing OnboardingController#sign_in (for 127.0.0.1 at 2013-06-18 09:17:17) [POST]
Parameters: {"authenticity_token"=>"Ij6v3x/QVZQ9pU1JPL433xMnzAJ/I4ndo+nFMCHK1Ok=", "action"=>"sign_in", "captcha_word"=>"asa", "date"=>{"month"=>"1"}, "user"=>{"username"=>"al", "ssn_third"=>"[FILTERED]"}, "continue.x"=>"-325", "continue.y"=>"-810", "controller"=>"onboarding", "dob"=>{"year"=>"12", "day"=>"1"}}
Here's the HTML that actually gets generated for the tag:
<form action="/onboarding/sign_in?authenticity_token=Ij6v3x%2FQVZQ9pU1JPL433xMnzAJ%2FI4ndo%2BnFMCHK1Ok%3D&captcha_word=asa&continue.x=-325&continue.y=-810&date%5Bmonth%5D=1&dob%5Bday%5D=1&dob%5Byear%5D=12&user%5Bssn_third%5D=3333&user%5Busername%5D=al" id="sign_in_form" method="post" novalidate="novalidate">
Any thoughts/suggestions are greatly appreciated! Thanks in advance!
Also, I'm doing client-side validation via the jQuery Validation plugin. I haven't included the code here as I don't think it's relevant, but I can provide it, if necessary.
There were actually two problems here:
I wasn't rendering the sign_in page in all the validation cases:
flash[:errors] = Messages['onboarding/invalid_creds']; render :sign_in; return unless #onboarding_user
The param names in sign_in.html.erb must be the same as the object being validated.
So, for example instead of this:
"text" %>
I needed this:
<%= text_field :onboarding_user, :username, :class => "text" %>
Hope this helps someone in the future!

Resources