Processing two unassociated Rails models' forms in one controller action - ruby-on-rails

I'm creating a Rails app that will take in input from two models and their respective forms, and then log into a website with Mechanize and do hundreds of tasks there.
The first form consists of the user's login information (the username and password, using the model User), and the second one is a long list of term names and their respective definitions (using the model Term and uploaded into the form as an Excel doc).
I have no need to associate these two models (unlike in similar SO questions, which seem to deal with nested models). Once this Mechanize task completes, I will destroy both models' objects from the database.
The two pieces of the app (logging in to the website; and uploading the terms and using them to interact with the website) both work perfectly in separate scripts.
My question is: How can I take in both models' information on one webpage and coordinate the controller(s) accordingly? In this situation, can I create both objects in one controller? (If not, that's fine, as long as there's an alternative; I'm game for whatever will get this to work.)
I'm posting some of my code below. I'm happy to answer any questions you may have. Please keep in mind I am pretty new at Rails, so is not very elegant code:
The User model:
class User < ActiveRecord::Base
attr_accessor :username, :password
end
And the Term model:
class Term < ActiveRecord::Base
attr_accessible :name, :definition
end
In my terms controller (the forms are located in the index action and the script is run in the show action):
def create
#term = Term.new(params[:term])
#user = User.new(params[:user])
if (#term.save && #user.save)
flash[:notice] = "Your terms have been sent for processing."
redirect_to terms_path
else
render :action => 'index'
end
end
def show
#term = Term.all
agent = Mechanize.new
page = agent.get('www.myurl.com')
#log into the website
#user.username = myform.field_with(:id => "userfield").value
#user.password = myform.field_with(:id => "passfield").value
#and then enter the term information into the website's forms
rest of Mechanize code goes here...
end
And in views/terms/index.html.erb:
#the login form:
<%= render 'loginform' %>
#the term file uploader:
<%= form_tag import_terms_path, multipart: true do %>
<%= file_field_tag :file %>
<%= submit_tag "Import" %>
<% end %>
<br>
<table id="terms">
<tr>
<th>Name</th>
<th>Definition</th>
</tr>
#displays the uploaded terms on the index page
<% #terms.each do |term| %>
<tr>
<td><%= term.name %></td>
<td><%= term.definition %></td>
</tr>
<% end %>
</table>
<p><%= link_to 'Update website with these terms', terms_update_terms_path %></p>
And in views/terms/_loginform.erb:
<%= form_for(#user) do |f| %>
<div class="field">
<%= f.label_tag(:username, 'Username') %><br />
<%= f.text_field_tag(:user, :username) %>
</div>
<div class="field">
<%= f.label_tag(:password, 'Password') %><br />
<%= f.password_field_tag(:user, :password) %>
</div>
<% end %>
And in views/terms/_termform.html.erb
<%= form_for(#term) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :definition %><br />
<%= f.text_area :definition %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

If you just need to save the data and truly don't want to associate the models, I would save the Term separately:
<%= form_for #user do |f| %>
<div class="field">
<%= f.label :username, 'Username' %>
<%= f.text_field :username %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="field">
<%= label_tag :name %>
<%= text_field_tag :name %>
</div>
<div class="field">
<%= label_tag :definition %>
<%= text_field_tag :definition %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Then in your controller:
#term = Term.new
#term.attributes = {
:name => params[:name],
:definition => params[:definition]
}
#term.save
If you are adding multiple term fields to the form, I would consider something like Cocoon, and just add an each loop for saving the Terms in the controller.

Related

rails form_for nested data doesnt show up

New to rails and getting confused on how to handle this. I am using rails 4. I am very stuck here and will try to talk through this problem.
I have a listings page which I am trying to add tags too. In my view (listings/new.html.erb) I have the following:
<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 %>
The form works correctly for putting in the listing, but the tagging form options do not even appear to allow for content.
my listings_conroller #new looks like this:
def new
if (!current_user.nil?)
#user = User.find(current_user.id)
#listing = #user.listings.build
#tagging = #listing.taggings.build
end
end
I want to be able to create a new listing with this form that also populates the database for the tags and I am very unsure on how to do this. I hope this is enough information, but if needed I have all the code here: https://bitbucket.org/r-s/ath/src . Very stuck on this any help would be appreciated.
Change it to:
<%= f.fields_for #tagging do |u| %>
Note the =.
You forgot to use builder:
<%= f.fields_for #tagging do |u| %>

Ruby on Rails, instead of update make new entry to model

I made a simple demo site, with an model for the patients name (name:string) and another model with the treatment (content:text). I created this "project" to learn more about the accepts_nested_attribute for tag and the fields_for tag.
Now my problem is that on the patient show page i created an nested formula for the treatment , like you can see here:
<p id="notice"><%= notice %></p>
<p>
<b>Name:</b>
<%= #patient.name %>
</p>
<ol>
<% for treatment in #patient.treatments %>
<li><%= treatment.content %></li>
<% end %>
</ol>
<%= form_for(#patient) do |f| %>
<%= f.fields_for :treatments do |builder| %>
<div class="field">
<%= builder.label :content %><br />
<%= builder.text_field :content %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<%= link_to 'Edit', edit_patient_path(#patient) %> |
<%= link_to 'Back', patients_path %>
So my problem is that in the builder.text_field :content better called the input shows up the last saved treatment from <%= builder.content %>, but i want that he does not update it instead i want to add new treatments! Hopefully somebody understands me! Thanks
I would create separate controller for creating only the treatment, eg.
# treatments_controller.rb
class TreatmentsController < ApplicationController
def create
#patient = Patient.find(params[:patient_id])
#treatment = #patient.treatments.new(params[:treatment])
if #treatment.save
redirect_to #patient
else
# handle unsuccessful treatment save
end
end
end
# routes.rb:
resources :patients do
resources :treatments, only: :create
end
# form:
<%= form_for #patient, #treatment do |f| %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_field :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You should also set #treatment variable in the patient#show action, like this:
#treatment = #patient.treatments.new

Setting a value sent from a link_to a partial in another view

So i have this link from a partial in a view:
<td><%= link_to 'Inscribir Ejemplares en la Carrera', home_carreras_path(#race, :meeting_id => meeting.id) %></td>
That link sends me to another view where two other partials are rendered.
The browser address looks like this:
http://0.0.0.0:3000/home/carreras?meeting_id=6
So you see that the value i sent from the link is there, and i want to pass that value, that number to one of the partials rendered in that view.
i haven't found how to do that, i searched a lot before asking. So please i hope someone here can help me. Thank you.
EDIT: ADDING MORE INFO
Controller:
class HomeController < ApplicationController
def index
render :layout => 'principal'
end
def carreras
#meeting_id = params[:meeting_id]
render :layout => 'principal'
end
end
Not much action there :/
The Partial where the hidden field is:
<%= form_for(race) do |f| %>
<ul>
<% race.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.hidden_field :meeting_id %><br />
</div>
<div class="field">
<%= f.label :carrera_num %><br />
<%= f.text_field :carrera_num %>
</div>
<div class="field">
<%= f.label :caballo_num %><br />
<%= f.text_field :caballo_num %>
</div>
<div class="field">
<%= f.label :caballo_nombre %><br />
<%= f.text_field :caballo_nombre %>
</div>
<div class="field">
<%= f.label :distancia %><br />
<%= f.text_field :distancia %>
</div>
<BR>
<div class="actions">
<%= f.submit "Inscribir Ejemplar" %>
</div>
<% end %>
If your controller actions for carreras, you can set an instance variable for the meeting_id.
def carreras
#meeting_id = params[:meeting_id]
# rest of controller action
end
#meeting_id will then be available to you throughout your rendered action.
You can supply your hidden_field tag with an options hash to set the value.
<%= hidden_field :meeting_id, value: #meeting_id %>

Associated model is not saving data when page is refreshed

Rails 3.1 RC4
I have a 1:1 association between User and Profile.
When I submit the new profile form, the data I've entered is displayed just fine (see screenshot: http://i.imgur.com/fY8YU.png), but when I refresh it the data is instantly wiped.
Could anyone tell me what is causing this?
Here's the submit form:
<%= form_for([#user, #user.build_profile]) do |f| %>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :picture %><br />
<%= f.text_field :picture %>
</div>
<div class="field">
<%= f.radio_button(:sex, "male") %>
<%= f.label(:sex, "Male") %>
<%= f.radio_button(:sex, "female") %>
<%= f.label(:sex, "Female") %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Here's the users_controller: https://github.com/imjp/SuperModel/blob/master/app/controllers/users_controller.rb
Here's the profiles_controller: https://github.com/imjp/SuperModel/blob/master/app/controllers/profiles_controller.rb
I'm not sure I agree with your approach. Why don't you do something like this:
In models/user.rb:
accepts_nested_attributes_for :profile
In controllers/users_controller.rb:
def new
#user = User.new
#user.build_profile
end
In views/users/_form.html.erb:
<%= form_for #user do |f| %>
<%= f.text_field :first_name %>
<%= f.fields_for :profile do |pf| %>
<%= pf.text_field :some_profile_field %>
<% end -%>
<%- end -%>
This isn't copied or tested, but it should work. On saving your user, the profile fields are sent along and validated with the user fields and are re-rendered when rendering the form again after a save error. This way you will keep full control over your form and its contents with minimal effort.

Work after user creation

I create a new user with basic fields as user name and password. Then I redirect to another page where the user is allowed to complete his profile. The page looks like this.
Ok, I created the user first. Then I redirected the user to complete his profile. The profile page looks like this
<h1>User successfully created</h1>
<h3>Would you like to complete your profile now?</h3>
<%= render #profile %>
<%= render #address %>
<%= button_to 'Save',{
:controller => "users",
:action => "update",
:id => #user.id,
:profile => #profile,
:address => #address
}, :method => :put %>
The code above executes the update action in the controller. However, I am getting nil for the #profile and #address objects. I guess the button_to is having no effect on the profile and address partials.
The address partial looks as follows
<%= form_for(#address) do |f| %>
<% if #address.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#address.errors.count, "error") %> prohibited this address from being saved:</h2>
<ul>
<% #address.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<fieldset>
<legend>Addresss</legend>
<div class="field">
<%= f.label :street_address %>
<%= f.text_field :street_address, :size => 40 %>
</div>
<div class="field">
<%= f.label :street_address_2 %>
<%= f.text_field :street_address_2, :size => 40 %>
</div>
<div class="field">
<%= f.label :city %>
<%= f.text_field :city, :size => 40 %>
</div>
<div class="field">
<%= f.label :state %>
<%= f.text_field :state, :size => 40 %>
</div>
<div class="field">
<%= f.label :zip_code %>
<%= f.text_field :zip_code, :size => 40 %>
</div>
<% end %>
I would appreciate if anyone would be able to help me on this.
The button_to method only creates a button which an be used to call an controller/ go to another page.
If you want to allow the user to modify fields, you need to use a form. Please read this guide on forms for more information, especially part 2 is of interest for your situation I guess.
Edit: You need a submit button in your form to submit it, not a button_to outside the form. If you want to have both partials submitted at the same time, you need 1 big form and a controller which is able to process the data of both models.

Resources