I'm hoping this is a simple question - I have the following helper code:
module ApplicationHelper
def add_feature_fields(feature_types, object_form_builder, actions_visible)
feature_types.length.times {object_form_builder.object.features.build}
i = 0
fields = object_form_builder.fields_for :features do |features_builder|
render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => feature_types[i], :form_actions_visible => actions_visible}
i = i + 1
end
end
end
The code is working as expected, except for the line i = i + 1. For some reason, this seems to be breaking the loop, and nothing is rendered. Evidently, I am doing this wrong somehow - perhaps fields_for is not a normal loop?
How can I increment i by 1 each time the loop runs?
I'm not sure about the below code, but something around this should work and fix the issue. Give a try
object_form_builder.each.with_index do |builder,index|
object_form_builder.fields_for :features, builder do |feature_builder|
render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => feature_types[i], :form_actions_visible => actions_visible}
end
end
I was able to get this working by doing the following:
module ApplicationHelper
def add_feature_fields(feature_types, object_form_builder, actions_visible)
feature_types.length.times {object_form_builder.object.features.build}
i = -1
object_form_builder.fields_for :features do |features_builder|
i = i + 1
render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => feature_types[i], :form_actions_visible => actions_visible}
end
end
end
I believe what was happening was that when I did i = i + 1 after I called render, the return value was the iterator and not render (since the method returns the last value).
Related
I'm reworking a Rails 2 website. Right now, I'm getting an error, and I think it's because a value is being submitted as blank instead of .nil. However, my attempts to keep it nil don't seem to be working. I appreciate any help you have to offer.
From Model, based on Make blank params[] nil
NULL_ATTRS = %w( start_masterlocation_id )
before_save :nil_if_blank
protected
def nil_if_blank
NULL_ATTRS.each { |attr| self[attr] = nil if self[attr].blank? }
end
View
I've got jQuery that adds a value to this hidden field when a start_masterlocation_id exists. I've also got jQuery that removes the field attribute when it does not exist.
<%= hidden_field :newsavedmap, :start_masterlocation_id, :id => "start-masterlocation-id-field" %>
Finally, here is the part of the controller that is throwing the error. This is the controller for the page that holds the form (Maptry), not the controller for Newsavedmap. I think I have to delete the #newsavedmap.id, #newsavedmap.mapname, and #newsavedmap.optimize lines now that I'm going with form handlers, but I don't think that's related to this error.
Controller
def maptry
#itinerary = Itinerary.find(params[:id])
if #itinerary.user_id == current_user.id
respond_to do |format|
#masterlocation = Masterlocation.find(:all)
format.html do
end
format.xml { render :xml => #masterlocation }
format.js do
#masterlocation = Masterlocation.find(:all)
render :json => #masterlocation.to_json(:only => [:id, :nickname, :latitude, :longitude])
end
end
if params[:newsavedmap_id]
#newsavedmap = Newsavedmap.find(:first, :conditions => {:id => params[:newsavedmap_id]})
#waypoint = Waypoint.find(:all, :conditions => {:newsavedmap_id => params[:newsavedmap_id]})
#newsavedmap.id = params[:newsavedmap_id]
#newsavedmap.mapname = Newsavedmap.find(:first, :conditions => {:id => params[:newsavedmap_id]}).mapname
#newsavedmap.optimize = Newsavedmap.find(:first, :conditions => {:id => params[:newsavedmap_id]}).optimize
if !#newsavedmap.start_masterlocation_id.nil?
#start_name = Masterlocation.find(:first, :conditions => {:id => #newsavedmap.start_masterlocation_id}).name
end
if !#newsavedmap.end_masterlocation_id.nil?
#end_name = Masterlocation.find(:first, :conditions => {:id => #newsavedmap.end_masterlocation_id}).name
end
else
#newsavedmap = Newsavedmap.new
end
else
redirect_to '/'
end
end
Error
This does not occur when a start_masterlocation_id is present in the database.
undefined method `name' for nil:NilClass
I solved this by ignoring the nil problem. Instead, I used
!#newsavedmap.start_masterlocation_id.blank?
This evaluates whether the data in the record is blank and then either does or doesn't do something. Obviously, this results in unwanted "blank" data being left inside my database, so it's not ideal, but it helped me move forward with the project. I'd appreciate any responses that deal directly with the nil issue and tell me how to have Rails ignore blank data in a form.
I've been trying to install and use the new sync realtime partials gem, but when it comes to putting the code in my views it all goes wrong.
This is my existing code, pre sync.
<%= render :partial => "tasks/table", :locals => { :assigned_to => true, :user_dashboard => false } %>
It now reads:
<%= sync partial: 'task_table', resource: #tasks %>
I've created a sync folder in my views, and a tasks folder, and added in _task_table.html.erb.
NoMethodError in Tasks#index
Showing /Users/callum/rails_projects/arc_app/app/views/tasks/index.html.erb where line #17 >raised:
undefined method model_name for WillPaginate::Collection:Class
In my tasks_controller.rb i have
def index
#tasks = Task.search(params[:search]).order(sort_column + " " + sort_direction).paginate(:per_page => 15, :page => > params[:page]).find_by_status(params[:status])
end
I'm quite new to rails but, I'm guessing its to do with the #tasks in my controller, I also process the table partial from a different controller with the same / similar error.
Use the following way and don't mix up all together:
def index
user_task = case params[:status].present?
when true then Task.where(:status => params[:status]).all
else Task
end
#tasks = user_task.paginate(:per_page => 15, :page => params[:page]).search(params[:search])
end
I'm a front end guy getting more and more into using sinatra. I'm building an app currently and am trying to find an elegant way to DRY up the routes in my myapp.rb file.
Currently I have these routes:
get '/' do
haml :content
end
get '/content' do
haml :content, :layout => :empty
end
get '/show_layout' do
haml :show_layout
end
get '/conversion' do
haml :conversion, :layout => :empty
end
get '/optout' do
haml :optout, :layout => false
end
get '/terms' do
haml :terms, :layout => :empty
end
With regards to the templates, I know I can do something like this to combine them:
get '/:name' do
haml params[:name].to_sym
end
But what about the layouts? There are only 2 layouts here, layout.haml and empty.haml (:layout, and :empty), 3 if you count :layout => false
Is this something that is best done using a hash? Something like:
layout_map = {
"" => "",
:content => "",
:show_layout => "",
:conversion => :empty,
:optout => false,
:terms => :empty
}
get '/:name' do
haml params[:name].to_sym, :layout => layout_map[:name]
end
Seems like its on the right track but I can't get it to work properly.
Thanks for all your help.
You can use your:
get '/:name' do
haml params[:name].to_sym
end
plus a before route that will set your layout:
before '/:name' do
layout_map = {
:content => "",
:show_layout => "",
:conversion => :empty,
:optout => false,
:terms => :empty
}
set :layout => layout_map[params[:name]]
end
This will set your layout according to params[:name] with every call. But be careful with .simming every route. If someone calls many 404s you create lots and lots of dead symbols which are not garbage collected and eventually will crash your app. Better do this:
get '/:name' do
halt 404 unless File.exist?("views/#{params[:name]}.haml")
time = File.stat("views/#{params[:name]}.haml").ctime
last_modified(time)
haml params[:name].intern
end
This will only create a symbol for params[:name] if there is a file with that name. So you're on the safe side because the symbol already exists.
Thanks for all your help everyone. Ended up going with this as my solution due to some other requirements of the app.
get "/:base_route/" do
haml :"#{params[:base_route]}/content", :layout => :"#{params[:base_route]}/layout"
end
get "/:base_route/:name" do
layout_map = {
:landing => :layout,
:content => :empty,
:show_layout => :layout,
:conversion => :empty,
:terms => :empty
}
haml :"#{params[:base_route]}/#{params[:name]}", :layout => :"#{params[:base_route]}/#{layout_map[params[:name].to_sym]}"
end
My user model has many projects, and each project has many invoices.
I am calling the following render
render :partial => "layouts/allInvoices", :collection => #projects, :as => :p
And inside the allInvoices, I wish to iterate over each project's invoices.
I can use
- p.invoices.each do |i|
But I'd rather use a collection. I'm not sure how to phrase it though
= render :partial => "layouts/invoiceItem", :collection => p.invoices, :as => :i
Doesn't work. Do I need to set up the nested iteration inside the controller?
Thanks
Do you mean something like...
= render "layouts/allInvoices", :p => #projects
Then
- # layouts/allInvoices
- p.invoices.each do |invoice|
= render "layouts/invoiceItem", :i => invoice
- # layouts/invoiceItem
= i.id # this gives id of Invoice
I want to display different types of objects in the same ajax called controller function. I want to render out when I send back an ajax call. The problem is I want the "title" attribute of one object and the "name" attribute of another object. I can't render 2 partials and can seem to figure out how to check the type of object an object is. How do I solve this problem?
Here is my current controller setup (NOT CORRECT)
#objects = Obj.find(:all,:conditions => ["name Like ?", "#{prefix}%"])
#moreObjects = ObjTwo.find(:all,:conditions => ["title Like ?","#{prefix}%"])
if #objects.empty?
render :text => "No Matches"
else
render :partial => 'one', :collection => #objects
end
if #moreObjects.empty?
render :text => "No Matches"
else
render :partial => 'two', :collection => #moreObjects
end
try something like
<%= obj.title if obj.respond_to?(:title) %>
Here's one option that doesn't involve checking its type - in your Obj and ObjTwo classes add a new method:
def fancy_pants
title
end
def fancy_pants
name
end
Then you can combine #objects and #moreObjects - you'll only need one if statement and one partial.
#search_domination = #objects + #moreObjects
if #search_domination.empty?
render :text => "No Matches"
else
render :partial => 'one', :collection => #search_domination
end
You could use Object.is_a? but that's not a very clean solution. You could also try mapping your data before presentation to help keep your views lightweight.