Passing text_field input value to a certain controller - ruby-on-rails

I am very new to Ruby and Rails, and I have come across a problem I can't seem to be able to solve:
In my rails app i have users which on the index site, called home, are displayed a couple of events.
If the user wants to "bookmark" these events he can click on a button next to the event an add it to his event_items list, which is just an "association"-controller I implented for the association between users and events (e.g. users has_many events and vice versa)
This all works fine, and this is how I have implemented the add functionality:
index.html.erb extract for home:
<h2>Events</h2>
<% #events.each do |event| %>​
​ <div>​<%= event.eventtitle %></div>
<%= button_to 'Add Event', event_items_path(event_id: event, user_id: session[:user_id]) %>
<% end %>
The button_to method works fine to add an event to the event_item list which just records the user_id and the event_id for an association in an even_items db-table.
Now I would like to allow the user to add a comment along to the event to the event_items db-table.
I can't seem to find a way of passing a text_field value to my event_items_path to add the comment to the event_items table in the db.
I guess I can't use the "button_to" method anymore because it is resolved in it's own form and thus I can't transmit any text_field information. So I created a new form... I can't get this form to pass the text_field information as parameters though:
new index.html.erb extract for home:
<h2>Events</h2>
<% #events.each do |event| %>​
<%= form_for :event_items, url: event_items_path(event_id: event, user_id: session[:user_id]) do |f| %>
<div>​<%= event.eventtitle %></div>
<%= f.label :event_comment %><br />
<%= f.text_field :event_comment %>
<%= f.submit %>
<% end %>
<% end %>
When I press the submit button, it still creates the event_item in my db-table, but withouth the event_comment. Checking the post transmission in my browser it doesn't seem to transmit the :event_comment.
It can only access the :event_id and :user_id in the parameters.
I would appreciate any help!
Update
I have just now realised, that when pressing the submit button from my new form above the :event_comment does get transmitted with the form.
Checking in Chromes DevTools, in Network>>Headers there is a post request which has event_id and user_id listed under Query String Parameters and the event_comment listed under Form Data as event_items[homeprediction]
Does anyone know how I can access the Form Data? Using params[:homepredictions] doesn't work in my event_items controller.

Found a solution now:
The :event_comment was being transmitted on submit. It is stored in Form Data as event_items[homeprediction].
This is what I did in the event_items controller to access the data:
def create
#user = User.find(params[:user_id])
event = Event.find(params[:match_id])
comment = params[:event_items]
#event_item = #user.event_items.build(event: event, event_comment: comment[:event_comment])
...
end
I saved the params[:event_items] hash to a new comment[] hash. And in the new comment[] hash I was able to access the :event_comment passed from the form field_tag.
Don't know if this is the most elegant/right way of doing it. But it works for now :-)

Related

Rails - Multiple forms, different Models (Objects), one submit button

I have a view with 3 forms, Schedules, Workouts and Exercises, all behaving like an edit form, each. And one submit(save) button in the all the view.
When I click on the save button. Every data changed on those forms should be updated after click.
What is the best solution for this ? Javascript updating each data separated ? How to do that ? Is there a more Rails way to do this easily ?
My difficulty is how to integrated all those models in one view, while all this is happening in the show(view) from the Student model.
If you're implementing something like a profile / edit page (where you can save all the records at once), the two ways I would look at would either be to save the forms via Ajax, or use a single submit method to handle them
Ajax
The ajax method would be the most conventional:
Every form you submit will go to the form's own update method in the backend
Each form could be handled by a single button, but it's best to split them up
#app/controllers/profile_controller.rb
def edit
#schedules = Schedule.all #-> not sure how many records you're using
#workouts = Workout.all
#exercises = Exercise.all
end
#app/views/profile/edit.html.erb
<%= form_for #schedule do |f| %>
<%= f.text_field :test %>
<% end %>
# -> other forms
<%= button_to "Save", "#", id: "save" %>
#app/assets/javascripts/application.js
$("#save").on("click", function() {
$("form").submit(); // we'll have to define the form to submit
});
Single
If you submit all the forms as one, you'll have to encase them all in a single form, as sending different errors. This could be achieved by using _, and handled in the backend by looping through the different params, saving each one individually.
I'd do this:
#app/controllers/application_controller.rb
def submit
types = %w(schedules exercises workouts)
for type in types do
type.constantize.update_attributes()
end
end
This allows you to create a form with the different data types submitted in the same action:
#app/views/profile/edit.html.erb
<%= form_tag profile_submit_path do %>
<%= fields_for #schedules do |f| %>
<%= f.text_field :title %>
<% end %>
# -> fields_for for the other objects
<% end %>
This will allow you to send the updated objects to your controller, allowing them to submit
If all of your models (Schedules, Workouts and Exercises) are associated, using fields_for should be a good option.
From the above link:
<%= form_for #person do |person_form| %>
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>
<%= fields_for :permission, #person.permission do |permission_fields| %>
Admin? : <%= permission_fields.check_box :admin %>
<% end %>
<%= f.submit %>
<% end %>
Read the guides.
You could have some simple javascript that iterates over all form tags and submits each of them.
Alternatively, if you are going to use javascript anyways, you could follow an AJAXish auto-save approach upon changing any field.
But I think it might be cleaner if you just had one form for multiple models, using fields_for.

insert multiple records to a single table from a single form

Generally if we can create only 1 record, say 1 user at a time from the form. But what if I want to create multiple users from a single form? There are no associations with other models. How can i do that?
You have to make a form with an array of users params .e.g
<%= from_tag '/users/create_multiple' do %>
<%= text_field_tag "users[][name]" %>
<%= text_field_tag "users[][name]" %>
<% end %>
In UsersController:
def create_multiple
params[:users].each do |user|
user = User.create(user)
end
end
You can add validation code as per your wishes,
visit here how to pass form params for multiple records http://guides.rubyonrails.org/form_helpers.html#basic-structures
One option is, write as many forms that you want for each model and submit all the forms once with Jquery.
This link will help you with submitting multiple forms
Multiple submit buttons/forms in Rails

conditionally exclude fields from rails form

The functionality I want to achieve with this is to have different fields based on the action the user is currently on.
The generic scaffold bundles the form into a partial and renders it in the new and edit actions. In a typical signup case, one may not want to update the password everytime the profile is updated. One way I used to solve this in the past is to create separate forms for new and edit; including the password in new only. Obviously, most fields repeat themselves. Is there a way to keep the partial but omit (thereby not updating) some fields on the form per action?
Let me assume you are building the form for user model.So in controller you will have
def new
#user = User.new
.....
end
def edit
#user = User.find(params[:id])
....
end
In the form partial use
<% if #user.new_record? %>
<%= f.field_type :field_name %>
<% end %>
This will not render the field during edit/update.
You can try it this way in one partial:
<% if params[:action] == "new" %>
<%= f.field_type :field_name %>
<% end %>
But you should think about the security because this doesnt keep away attackers from adding POST fields manually to write to fields that aret displayed as Fields on you form!
You can check whether the active record object being passed to the view (such as #user) is a new record or and old one using the method 'new_record?'. Based on this, you can decide what fields you want to display.
Alternatively, you could also have a partial and then pass it some value (most likely a Boolean) and based on that value you can decide which fields to render.
This can been done like:
render :partial => 'partial_name', :locals => {:bool => true}
And then in your partial do
<% if bool == true %>
<%= f.xyz_tag :name %> //whatever field you want
<% end %>

rails - form to disply non-input type fields in nested form

I guess this is a newbie question, but what is the syntax in a form to show contents of fields not as a text box/area, but rather like label would appear.
<% form_for #user do |f| %>
<% f.fields_for :user_ingreds do |builder| %>
<p>
<%= builder.??? %>
</p>
<% end %>
<% end%>
user has_many :user_ingreds and accepts_nested_attributes_for :user_ingreds.
Basically I want to make a list of user_ingreds where the user can't edit the data but can remove the record from the list via a button.
However the fields_for builder doesn't recognize a direct call to to the fields in UserIngred model (ie, builder.user_id throws and error.
If you want to make a non-editable list of the ingreds with a button to remove them, then don't make a form.
Instead, display your data and a button beside them created with link_to and pointing to your delete function.
If ever you want to really display the content of your form variable, you can access it this way:
builder.object.user_i

ruby on rails will paginate between dates

In the application there is a default report the user see's listing all the calls for a certain phone. However, the user can select a date range to sort the list from. Doing that, everything works correctly, but when the user selects the date range and changes to the second page, the date-range is lost and it goes back to the default view for the second page.
In my controller, I'm checking to see if the date_range param is being passed in. If it isn't, I display the entire listing, if it is, I display the records in between the certain date range.
The problem is, when I click on a new page, the new parameter doesn't include the old date-range that it should.
How do I go about doing this, I was thinking of doing some class level variable test but that isn't working out the way I thought. And I'm pretty stuck.
I don't have the code right in front of me, but if I remember correctly it's something like this:
<% form for :date_range do |f| %>
<%= f.calendar_date_select :start %>
<%= f.calendar_date_select :end %>
<%= f.Submit %>
<% end %>
And in the controller, it's something like:
if params[:date_range] == nil
find the complete listings without a date range
else
find the listings that are within the date range
end
The main problem is that you're using a POST request when submitting the form, but will-paginate uses a GET request. You should also use form_tag instead of form_for because form_for will nest the fields in a hash which is not possible with GET.
<% form_tag items_path, :method => 'get' do %>
<%= calendar_date_select_tag :start_date %>
<%= calendar_date_select_tag :end_date %>
<%= submit_tag "Submit", :name => nil %>
<% end %>
Then check params[:start_date] and params[:end_date] directly. You'll need to change items_path to whatever page you want the form to go to.
This is untested but it should get you in the right direction.
You could modify the link_to (assuming that's how you go through pages) so that it passed the date_range param.
= link_to 'Next', #whatever_path, :date_range => #date_range
where #date_range could be set in your controller by capturing your params in an instance variable.. .
But there may be a better solution.

Resources