Create missing objects before form loads in rails - ruby-on-rails

I am just trying to make my form display a blank field for each item that has not yet been created. I've done this successfully using the build method for more simple forms but I'm not sure how to do it for this case. Is the strategy I'm using to do this wrong or am I making a simple syntax mistake?
Here's the basic model setup:
A Comp has many Rounds and many Teams. A Round has many Items. Each Team has only 1 Item per Round
So when the form is loaded, if a team has not already created an item, I want there to be a blank item created for that team so that it shows up in the form and can be edited for that team.
I tried 2 different methods in my controller and neither has worked:
Method 1:
def edit_admin
#comp = Comp.find(params[:comp_id])
#round = #comp.rounds.find(params[:round_id])
team_ids = #round.items.all(:select => :team_id).collect(&:team_id)
#comp.teams.each do |team|
if team_ids.include? team.id == false
new_item = #round.items.new(:team_id => team.id, :round_id => #round.id)
new_item.save
end
end
end
def update_admin
#comp = Comp.find(params[:comp_id])
#round = #comp.rounds.find(params[:round_id])
if #round.update_attributes(params[:round])
redirect_to(edit_comp_path(#comp))
else
render 'edit_admin'
end
end
Method 2:
Essentially the same thing but I defined a method to run before the page loads:
before_filter :build_new_items, :only => :edit_admin
private
def build_new_items
#comp = Comp.find(params[:comp_id])
#round = #comp.rounds.find(params[:round_id])
team_ids = #round.items.all(:select => :team_id).collect(&:team_id)
#comp.teams.each do |team|
if team_ids.include? team.id == false
new_item = #round.items.new(:team_id => team.id, :round_id => #round.id)
new_item.save
end
end
end
The form looks like this (the view is called edit_admin.html.erb):
<%= form_tag update_admin_comp_round_items_path(#comp,#round), :method => :put do %>
<% for item in #round.items.all %>
<%= "Team: " + #comp.teams.find(item.team_id).team_name %> <br />
<%= fields_for 'round[items_attributes][]', item do |f| %>
<%= f.label :item_name %>
<%= f.text_field :item_name %> <br />
<%= f.hidden_field :id, :value => item.id %> <br />
<% end %>
<% end %>
<p><%= submit_tag "Submit" %></p>
<% end %>
Thanks.

Answering my own question since no one else did: I got method B to work with a very minor tweak. All it needed was parentheses around the value after "include?", like so:
if team_ids.include?(team.id) == false.
I figured this out by playing with each line of code in the rails console.
Method A may work as well but since I got method B to work, I haven't yet tried it.
UPDATE: method A also works

Related

Redirecting to "show" view of a model object when searched by attributes (NOT id)

I have a form where users look for a particular bill by some attributes of that bill, namely the "Congress Number", "Bill Type", and "Bill Number", as in 114-H.R.-67 . I want to "show" the appropriate bill, but to do that I have get the appropriate bill model in a separate action which I've called "find_by_attributes". Inside this action I perform:
#bill = Bill.find_by( params ).first
which correctly acquires the appropriate bill's id.
Now I simply want to redirect to the "show" method of this bill, as in the url
".../bills/[#bill.id]"
As of right now, at the end of my "find_by_attributes" action I do
redirect_to bills_path(#bill)
which correctly loads the show.html.erb with #bill, but does not change the url (the url is still shows the "find_by_attributes" action followed by a long query-string, instead of the clean "/bills/[:bill_id]".
How can I restructure my code to achieve the neat redirect that I desire?
Full code below:
THE FORM
<%= form_tag("bills/find_or_create", :method => :get ) do |f| %>
<%# render 'shared/error_messages', object: f.object %>
<%= fields_for :bill do |ff| %>
<%= ff.label :congress, 'Congress (i.e. 114)' %>
<%= ff.number_field :congress, class: 'form-control' %>
<%= ff.select :bill_type, options_for_select(
[['House of Representatives', 'hr'],
['Senate', 's'],
['House Joint Resolution', 'hjres'],
['Senate Joint Resolution', 'sjres'],
['House Concurrent Resolution', 'hconres'],
['Senate Concurrent Resolution', 'sconres'],
['House Resolution', 'hres'],
['Senate Resolution', 'sres']]
)
%>
<%= ff.label :bill_number, 'Bill number (i.e. 67)' %>
<%= ff.number_field :bill_number, class: 'form-control' %>
<% end %>
<%= submit_tag "Submit", class: "btn btn-primary" %>
<% end %>
THE CONTROLLER ACTIONS
def find_by_attributes
#bill = Bill.where(bill_params).first_or_create(bill_attributes)
redirect_to bills_path(#bill)
end
def show
puts bill_params
if params[:bill]
#bill = Bill.where(bill_params).first_or_create do |bill|
bill.attributes = bill_attributes
end
else
#bill = Bill.find(params[:id])
end
#subjects = Subject.where("bill_id = ?", #bill[:id])
#bill_comments = Comment.where("target = ?", #bill[:id])
end
ROUTES FILE
...
resources :bills do
get :find_by_attributes
end
...
EDIT
I make use of the turbolinks gem in my rails application.
the thing I see here is that you are calling to
redirect_to bills_path(#bill)
that in theory is not the show path, you just need to remove the "s"
redirect_to bill_path(#bill)
and as a side comment, in this line, you don't need the first part, because find_b, finds the first record matching the specified conditions, you can remove that part.
#bill = Bill.find_by( params )

Create with multiple params issue

I have a controller that looks like this:
def new
#columns = Column.where(:table_id => #table.id)
#row = Row.new(id: #table.id)
end
def create
row_params.each do |row_param|
#row = Row.new(row_param)
#row.column_id = params["column_id"]
if #row.save
redirect_to collection_rows_path, notice: 'item was successfully created.'
else
render action: 'new'
end
end
end
I have a form that looks like:
<%= form_for [#table, #row] do |f| %>
<% #columns.each do |column| %>
<%= column.id %>
<%= hidden_field_tag :column_id, column.id %>
<%= f.label :data %><br>
<%= f.text_field :data %>
<% end %>
<%= f.submit %>
<% end %>
Basically, I'm trying to send multiple params and have them inserted with the column. But I keep getting this error:
undefined methodstringify_keys' for ["data", "No"]:Array` when there is two columns which means there is two text fields and I insert "Hello" in the first one, and "No" in the second.
Two things: Why is it only reading the "No" on the second one instead of both the "Hello" and "No"? And also why am I getting this error?
Thanks for all help!
Answers to your questions:
It is only reading "No" which is your input in the last "Data" text_field since the two text_fields generated in your form_for save their input value in the same params key which is params[:row][:data]. What happens then is the latest value saved to the params[:row][:data] key overrides any previous value it had.
The error undefined method stringify_keys' for ["data", "No"]:Array happens because you create 2 text_fields with the same name which is :data. When you submit the form, an Array is being submitted instead of a String that Rails expects when using text_field.
Solution to your problem:
This seems like an ideal use case for using a nested model form. Basing on your code, it looks like Row belongs_to Table. So in your Table model you'll need to add this code:
#app/models/table.rb
accepts_nested_attributes_for :row
Then add the following code in your RowsController:
#app/controllers/rows_controller.rb
def new
#columns = Column.where(:table_id => #table.id)
#columns.each do |column|
#table.rows.build(column_id: column.id)
end
end
def create
#table = Table.new(table_params)
if #table.save
redirect_to collection_rows_path, notice: 'item was successfully created.'
else
render :new
end
end
private
def table_params
params.require(:table).permit(rows_attributes: [:data, :column_id])
end
Then in your 'rows#new' view:
#app/views/rows/new.html.erb
<%= form_for #table, url: rows_path ,method: :post do |f| %>
<%= f.fields_for :rows do |r| %>
<%= r.object.column.name %>
<%= r.hidden_field :column_id, value: r.object.column_id %>
<%= r.label :data %><br>
<%= r.text_field :data %>
<% end %>
<%= f.submit %>
<% end %>
What the above code will do is allow you to create multiple rows for a column according to the number of columns the table has. This won't work though if a #table has no #columns yet. This assumes that you've created #columns for the #table already. Basing on your code though, it seems like that's already what you're doing.
you want to store 'data' as array in Row
In Rails model Row add
serialize :data, Array
in view
text_field_tag 'row[data][]'
You are getting only 'No' because form for does not know its an array so , it picks the last one And you are getting this error because rails does not know you want to store it as array , it excepts a string but got an array instead.

Unable to display text from Rails ActiveRecord errors.full_message

Ok, I've looked over results for this off and on all day (including search all over StackOverflow)...
In Rails 3.2.X and Ruby 1.9.3 I have a remote form. The form is working correctly and saving when valid, and not saving when not valid. However I can't get back the actual errors (and I've tried a bunch of different ways).
Here's the form (haml)
= form_for #lead, :remote => true, :validate => false do |f|
.span6
%ul
%li
= f.label "Name*"
= f.text_field :name
%li
= f.label "Company*"
= f.text_field :company
...
%li
= f.label :state
= select_tag :state, options_for_select(us_states)
%li
= f.label "Email*"
= f.text_field :email
.actions
= f.submit '', :id => "contactsubmit"
Here's the relevant spot in the controller:
def create
#lead = Lead.new(params[:lead])
respond_to do |format|
if #lead.valid?
format.js
else
format.js
end
end
end
And here's my view (create.js.erb) where I keep failing...
<% if #lead.errors.count == 0 %>
$('#error_explanation').fadeOut(500);
$('#learn-more .form').fadeOut(500, function() {
$('#learn-more #form-response').fadeIn(500);
});
<% else %>
$('#error_explanation').fadeIn(500);
<% #lead.errors.full_messages.each do |msg| %>
#never shows any messages. If I do #lead.errors.each do |error|
#it shows the field name, but not the body...?
$('#error_explanation').append('<%=content_tag(:p, msg)%>');
<% end %>
<% end %>
I know that commment isn't valid in there, I added it to show what I've tried.
I've tried a million different ways of showing the error message here. Everything else is working. I even added a counter in there (when not using msg) and it did show the four field errors. Any advice? Using similar code in another project (in a traditional view) w/o problem.
Make sure you're using escape_javascript anytime you run into troubles like this. Any quotes that might be inside the content or generated by a method like content_tag can break your JS.

Rails linking form submission to object

In a rails project I have two entities, Users and Institutions, they have a many-to-many relationship.
The views for them are set up to create new users and institutions but I want to have another view for linking the two.
In rails console all I have to do is
myuser.institutions << the_institution_i_just_created
The controller can do some of the work but how do I handle the submissions and the forms? I want to use a selection box so that the input is limited to the Institutions already in existence.
<select id="institution_selection" name="institution_sel">
<% selections = []
Institution.all.each do |institution|
pair = [institution.name, institution.id]
selections.concat([pair])
end
%>
<%= options_for_select(selections) %>
</select>
So the question in summary is how do I map this submission to an object so that in the controller I can do add it to the relation?
The solution was:
Alright, so this is the solution I came up with, I'm sure there is a better way to go about it and I'll continue to look into it but at least I got something close to what I was aiming for
def test
if !session[:user]
redirect_to users_path, notice: "Please login first"
end
if params[:institution]
#user = User.find(session[:user])
#institution = Institution.find(params[:institution][:id])
#user.institutions << #institution
redirect_to #user, notice: "Institution was successfully added "
end
end
and for the view
<%= form_tag("/users/test", :method => "post") do %>
<%= collection_select :institution, :id, Institution.all, :id, :name %>
<%= submit_tag("Search") %>
<% end %>
Use collection_select
<% from for #instancevar do |form| %>
<%= form.collection_select :institution_id, Institution.all, :id, :name %>
# Do other stuff....
<% end %>

Passing ActionView::Helpers::FormBuilder to a partial

I am atempting to dinamically create form elements given a certain AJAX request.
This is my setup:
View:
<%= link_to 'Next', check_unique_id_students_path, :remote => true %>
<div id="guardian_student_details"></div>
Controller:
def check_unique_id
#student = Student.new
#this_form = ActionView::Helpers::FormBuilder.new(:student, #student, #template, {}, proc{})
end
JS:
jQuery("#guardian_student_details").html("<%=escape_javascript(render :partial => "student_details", :locals => { :s => #this_form }) %>");
Partial:
<% puts s.text_field :first_name %>
<% puts s.field_helpers %>
For debugging purposes i placed the following lines at the very beginning of my partial:
<% puts s.class.to_s %>
<% puts s.object.to_s %>
This prints out :
ActionView::Helpers::FormBuilder
Student
This should work. However rails is giving the following error:
ActionView::Template::Error (undefined method `text_field' for nil:NilClass):
1: <% puts s.class.to_s %>
2: <p>
3: <%= s.text_field :first_name, :class => 'text_input is_empty' %>
4: <%= s.label :first_name %><strong>*</strong>
5: </p>
6:
app/views/students/_student_details.html.erb:3:in _app_views_students__student_details_html_erb__2485891544130782916_2214680440'
app/views/students/check_unique_id.js.erb:2:in_app_views_students_check_unique_id_js_erb__3504800328150418937_2214933160'
Which implies that "s" is NIL something I verified just 2 lines before. Does anybody have any ideas? i dont know if this has something to do with the "#template" variable initialized in the controller. Which i played around with and accepts practically anything and if printed is nil.
Any help would be appreciated. Thanks
Final note:
I tried to implement this: AJAX update of accepts_nested_attributes_for partials
For anyone needing to build a form builder in the controller, view_context still works there. Using Rails 4.1.4:
#object = Object.new
#f = ActionView::Helpers::FormBuilder.new(:object, #object, view_context, {})
In the view, I've found that 'view_context' does not work in Rails 3.1. Instead try 'self' when creating a FormBuilder object.
s = ActionView::Helpers::FormBuilder.new(:student, #student, self, {}, proc{})
Try this in a console :
s = ActionView::Helpers::FormBuilder.new(:student, #student, #template, {}, proc{})
s.text_field :first_name
You will have the same error. I think the problem come from your creation of the form_builder object, even if I don't know the exact mistake...
Your solution seems to me to be a little much complex. You can try this solution :
#html.erb
<% form_for #student do |f| %>
<div id='guardian_student_details' class='hide-this-block'>
<%= render :partial => "student_details", :locals => { :s => f }) %>
</div>
<% end %>
#js
jQuery("#guardian_student_details").show();
Generally, I prefer keep javascript and ruby separated.

Resources