update_attributes with none-standard form - ruby-on-rails

I have cobbled together a form due to some oddities in my code and routes. Things work for adding data to the database, but I can't quite seem to figure out how to update data. Here is some code.
new.html.erb
<% form_tag '/list' do %>
Episodes Completed:
<%= text_field_tag "completed" %>
Watch Status
<%= collection_select(nil, 'id', #show_status, :id, :state) %>
<%= hidden_field_tag('show_id', #show.id) %>
<%= submit_tag 'Add' %>
<% end %>
edit.html.erb
<% form_tag("/list/#{#show_completion.show.id}", :method => :put ) do %>
Episodes Completed:
<%= text_field_tag "completed", #show_completion.episodes_completed %>
Watch Status
<%= collection_select(nil, 'id', #show_status, :id, :state) %>
<%= hidden_field_tag('show_id', #show_completion.show.id) %>
<%= submit_tag 'Edit' %>
<% end %>
Here is the controller's Create and Update methods
def create
#show_completetion = ShowCompletionStatus.new
#show_completetion.user_id = current_user.id
#show_completetion.episodes_completed = params[:completed]
#show_completetion.status_state_id = params[:id]
#show_completetion.show_id = params[:show_id]
#show_completetion.save
end
def update
#show_completion = ShowCompletionStatus.find(params[:id])
#show_completion.episodes_completed = params[:completed]
#show_completion.status_state_id = params[:id]
#show_completion.show_id = params[:show_id]
if #show_completion.update_attribute('episodes_completed', params[:completed])
redirect_to "/list/#{current_user.username}"
else
redirect_to "/list/#{params[:id]}/edit"
end
end
Here are my routes for these:
match "list/" => "list#create", :via => :post
match "list/new/:show_id" => "list#new", :constraints => { :show_id => /[0-9]+/ }
match "list/:id/edit" => "list#edit", :constraints => { :id => /[0-9]+/ }, :via => :get
match "list/:id" => "list#update", :constraints => { :id => /[0-9]+/ }, :via => :put
I have been trying different things to get this to work for the better part of 4 hours now. I think I am just missing something, but I just can't see it.
Is there a better way to do the form that makes it work better?
Any help is appreciated.

I solved this issue by making a hash and passing it to the update attributes with the key value pairs of what the objects attributes would be. Since updates_attributes takes a hash and not an object it was a simple solution once the connection was made.

Try to replace your update_attribute call for a save call.
Also, if you're writing everything from scratch instead of using the builtins, try to use save! instead of save: it will raise an exception if it fails, unlike the plain save that just returns false.

Related

Params to controller

In my project I got a view, in this view I have a date input like this:
<%= form_tag installations_path, :method => :csv, :class => 'form-search' do %>
<%= select_date(date = Date.current, options = {}, html_options = {}) %>
<%= submit_tag "Save" %>
<% end %>
In my controller Installation I got a method with the name "csv" this method generate a Csv. Example:
def csv
#consumption = current_user.get_consumptions(params[:year])
respond_to do |format|
format.html
format.csv { send_data #consumption.to_csv }
end
end
When I execute the view I receive this error:
param is missing or the value is empty: installation
The problem is that in my installations_params I have require(:installation) cause I use object installation in others methods.
def installation_params
params.require(:installation).permit(:year,...)
end
What is the best way to resolve this problem ?
The request log may help you firstly.
If you generate the csv as a GET request, then change the code
from:
<%= form_tag installations_path, :method => :csv, :class => 'form-search' do %>
to:
<%= form_tag csv_installations_path, :method => :get, :class => 'form-search' do %>
Make sure the csv_installations_path is exist.
Then, you can get the year params as params[:year] if your input named year.
At last, You don't use any install_params in csv method
Hope it helps you.

Why does this select field appear multiple times in my Rails form?

I've got a Rails application that is using nested forms. Details follow and I tried this solution (Rails 3 Nested Models unknown attribute Error), but for some reason, the field is repeating multiple times instead of listing and saving the options correctly. Thanks in advance for your help!
Model information for Newsavedmaps
has_many :waypoints, :dependent => :destroy
accepts_nested_attributes_for :waypoints
Newsavedmap_controller
def new
#newsavedmap = Newsavedmap.new
waypoint = #newsavedmap.waypoints.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #newsavedmap }
end
end
def edit
#newsavedmap = Newsavedmap.find(params[:id])
if #newsavedmap.itinerary.user_id == current_user.id
respond_to do |format|
format.html # edit.html.erb
format.xml { render :xml => #activity }
end
else
redirect_to '/'
end
end
Maptry View
<% form_for #newsavedmap, :html=>{:id=>'createaMap'} do |f| %>
<%= f.error_messages %>
<% f.fields_for :waypoint do |w| %>
<%= w.select :waypointaddress, options_for_select(Waypoint.find(:all, :conditions => {:newsavedmap_id => params[:newsavedmap_id]}).collect {|wp| [wp.waypointaddress, wp.waypointaddress] }), {:include_blank => true}, {:multiple => true, :class => "mobile-waypoints-remove", :id =>"waypoints"} %>
<% end %>
<% end %>
When I use the above code, my form works correctly, but submitting it gives me this error:
UnknownAttributeError (unknown attribute: waypoint)
When I change ":waypoint do |w|" to ":waypoints do |w|" in the view, the select field disappears when the user is creating a new record, and in the edit view, the select field appears several times (however many waypoints the user saved in the record.)
How can I get this form field to work properly?
EDIT 1
Here is my latest attempt. For new records, the select field does not appear. However, in the edit view, the select field appears multiple times. This is a Rails 2 application, FYI. Taking a cue from the comments, I used a collection_select approach (not collection_for_select because I couldn't find documentation for that.) Again, I appreciate your help!
<% f.fields_for :waypoints do |w| %>
<%= w.collection_select( :waypointaddress, #newsavedmap.waypoints, :waypointaddress, :waypointaddress, {:include_blank => true}, {:id =>"waypoints"} ) %>
<% end %>
Your form has the following problems.
Use f.fields_for :waypoints since the argument needs to match the name of the association.
Use collection_select rather than select, since you have an ActiveRecord model behind that field.
So, taking that into account, you could try this for your form:
<% form_for #newsavedmap, :html => { :id => 'createaMap' } do |f| %>
<%= f.error_messages %>
<% f.fields_for :waypoints do |w| %>
<%= w.collection_for_select :waypoint, :waypointaddress, #newsavedmap.waypoints, :waypointaddress, :waypointaddress, { :include_blank => true }, { :multiple => true, :class => "mobile-waypoints-remove", :id =>"waypoints" } %>
<% end %>
<% end %>
The API for collection_select is a bit tricky to get right. I usually need a few attempts as well. This previous SO question may help clear things up: Can someone explain collection_select to me in clear, simple terms?

Rails 3: Can't add correct route to legacy code

Believe you can help me.
I'm trying to add new functionality to legacy code (Typo). But it seems that there is some problem about routing.
In the project routes are generated the following way:
%w{advanced cache categories comments content profiles feedback general pages
resources sidebar textfilters themes trackbacks users settings tags redirects seo post_types }.each do |i|
match "/admin/#{i}", :to => "admin/#{i}#index", :format => false
match "/admin/#{i}(/:action(/:id))", :to => "admin/#{i}", :action => nil, :id => nil, :format => false
end
My functionality is about merging articles. For that I've added new action in the /admin/content controller:
def merge
#some code here
end
A piece of a view partial (_form.html.erb) added by me:
<% if current_user.admin? and !#article.id.nil?%>
<div class=''>
<h4><%= _("Merge Articles") %></h4>
<%= label_tag :merge_with, 'Article ID' %><%= text_field_tag :merge_with, nil, :size => 20 %>
<%= button_to 'Merge', admin_content_merge_path(:id => #article.id) %>
</div>
<%end%>
This partial is rendered by another partial (_edit.html.erb)
<%= form_tag(form_action, :id => "#{form_type}_form", :enctype => "multipart/form-data", :class => className) do %>
<%= render :partial => "form" %>
<% end %>
And finally _edit.html.erb is rendered by view new.html.erb
<%= render "admin/shared/edit", { :form_type => "article", :form_action => { :action => "new", :id => #article.id , :class => ('autosave')} } %>
The problem is how to write a correct route for the controller action above which will allow me to render an edit page containing newly merged article. I wrote:
match "/admin/content/merge/:id" => "admin/content#merge",:as => 'admin/content/merge'
rake routes output:
admin_content_merge /admin/content/merge/:id(.:format) {:controller=>"admin/content", :action=>"merge"}
But the new or edit action is being invoked as I can see.
Apparently, my route is wrong, isn't it?
Could you please help me with this.
Thanks in advance!
Update
Up-to-date new.html.erb:
<% #page_heading = _('New article') %>
<%= render "admin/shared/edit", { :form_type => "article", :form_action => { :action => "new", :id => #article.id , :class => ('autosave')} } %>
<% if current_user.admin? and !#article.id.nil?%>
<%= form_tag "/admin/content/merge/#{#article.id}" do %>
<h4><%= _("Merge Articles") %></h4>
<%= label_tag :merge_with, 'Article ID' %>:
<%= text_field_tag :merge_with %><br />
<%= submit_tag "Merge" %>
<% end %>
<% end %>
Read the hint from the course:
HINT:Nesting is invalid in HTML.
That means that you can't nest form tags, don't put the form tag in another form tag, your nested form wont be able to do a correct action.
Since you have to put your code at the end of the page, try and see how to do it with having your merging form tag below the main edit article form tag. So basically you can find where the big form tag ends and put it below it.
Try to see if you can figure it out, and if not, don't hesitate to ask :)
Btw. I think everybody had some problem with this

Ruby on Rails: Why a select box does not show the current object value?

Here is the relevant code from views/products/edit.html.erb:
<%= form_for(:product, :url => {:action => 'update', :id => #product.id}) do |f| %>
<%= render(:partial => "form", :locals => {:f => f}) %>
<%= submit_tag("Update Product") %>
<% end %>
from views/products/_form.html.erb:
<%= select_with_new_option(f, :shop, :name, :id) %>
and from helpers/products_helper.rb:
def select_options_with_create_new(objects, text_field, value_field, options={})
object = objects.to_s.singularize
all_objects = object.capitalize.constantize.all
all_objects = all_objects.sort_by(&options[:order_by]) if options.has_key?(:order_by)
select_options = all_objects.map{ |obj| [obj.send(text_field), obj.send(value_field)] }
select_options << [wrap_create_new_option("create new #{object}".titleize), "new_#{object}"]
options_for_select(select_options)
end
def wrap_create_new_option(str)
">> #{str} <<"
end
# By default, sorts by 'text_field'.
def select_with_new_option(f, object, text_field, value_field)
f.select(:"#{object}_id", select_options_with_create_new(object.pluralize, text_field, value_field, :order_by => text_field))
end
I expect the select box to be #product.shop_id by default, but this is not true (the first option is always the default value).
What am I missing ?
Alright, I got it. Just remove options_for_select(select_options) in the select_options_with_create_new method.
The options_for_select assembles the 2-d array select_options into a string of html options, which is accepted by the select form helper, however, without assigning the selected attribute. Just pass the 2-d array to the select method as the second argument, it would assign the selected automatically.
I think that, in this case, all you need to do is make sure you set #product in your edit action:
def edit
#product = Product.find(params[:id])
end
Then change your first line:
<%= form_for(:product, :url => {:action => 'update', :id => #product.id}) do |f| %>
to
<%= form_for(#product, :url => {:action => 'update', :id => #product.id}) do |f| %>
The first code block will certainly update the proper product, but you'll only see the current values reflected if you generate a form_for #product, with that #product variable set.

how to get simple search in rails based on RailsCasts tutorial?

I followed the RailsCasts tutorial to do a simple search with autocomplete, but it doesn't work. :(
view/vendors/index:
<% form_tag vendors_path, :method => 'get' do %>
<%= text_field_with_auto_complete :vendor,
:name,
{},
{:method => :get, :class => 'textbox'} %>
<%= submit_tag "Search", :name => nil %>
<% end %>
</div>
<%= #searchvendor.id %>
<%= #searchterm %>
I included #searchterm and #searchvendor.id as validation steps.
So this should call the controller => vendor, action=> index:
def index
#searchterm = params[:vendor][:name]
#searchvendor = Vendor.search('checkpoint')
And the search method is created as follows for the vendor/model:
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
The output?
#searchterm does show the value that is inputed as that shows up in the URL as vendor[name]=?
#searchvendor.id is a long string and #searchvendor.name shows an error, name not a method.
I'm stumped. Help...please?
LINK to the Tutorial:
http://railscasts.com/episodes/37-simple-search-form
Should you not be passing in your #searchterm into your Vendor.search method? Passing 'checkpoint' each time probably isn't going to do the trick.
#searchvendor is going to contain an Array as you are doing find(:all). You'll need to iterate over the array and do .name on each item.

Resources