Nested content_tag throws undefined method `output_buffer=` in simple helper - ruby-on-rails-3

I'm trying to create a simple view helper but as soon as I try nest a couple of content tags it will throw NoMethodError: undefined method `output_buffer=' for
def table_for(list, &proc)
t = Table.new
proc.call(t)
t.render_column(list)
end
class Table
include ActionView::Helpers::TagHelper
attr_accessor :columns, :block
def initialize
#columns = Array.new
end
def col(name)
#columns << name
end
def render_column(list)
content_tag :table do
list.each do |c|
content_tag :td, c
end
end
end
end
Any hints of what's wrong? I've also seen that there's a XmlBuilder is that one better for my purpose?

ActionView::Base has built into it the Context module, which provides the methods output_buffer() and output_buffer=().
So you can solve your problem either by having your class do:
include ActionView::Context
Or even more simply:
attr_accessor :output_buffer

I think there were some changes about this in 3.0, but in previous versions the trick was to pass self:
def table_for(list, &proc)
Table.new(self)
# ...
def initialize(binding)
#binding = binding
#...
def render_column
#binding.content_tag :table do
# ...
end
end
I'm not sure if this is still how it's done in rails 3.
Another thing to fix in ordere for the code to work is to save the output of the inner content_tag somewhere, as with each the content is generated and then discarded. One of the possible solutions:
def render_column(list)
#binding.content_tag :table do
list.inject "" do |out, c|
out << #binding.content_tag(:td, c)
end.html_safe
end
end

With help from Nested content_tag throws undefined method `output_buffer=` in simple helper I ended up with the following solution inspired by the API for Formtastic.
<%= table_for(#users) do |t| %>
<% t.col :name %>
<% t.col :email %>
<% t.col :test, :value => lambda { |u| u.email }, :th => 'Custom column name' %>
<% t.col :static, :value => 'static value' %>
<% end %>
Using the output_buffer directly and probably reinventing the wheel the code looks like
module ApplicationHelper
def table_for(list, &block)
table = Table.new(self)
block.call(table)
table.show(list)
end
class Column
include ActiveSupport::Inflector
attr_accessor :name, :options
def initialize(name, options = {})
#name = name
#options = options
end
def td_value(item)
value = options[:td]
if (value)
if (value.respond_to?('call'))
value.call(item)
else
value
end
else
item[name]
end
end
def th_value
options[:th] ||= humanize(name)
end
end
class Table
include ActionView::Helpers::TagHelper
attr_accessor :template, :columns
def initialize(temp)
#columns = Array.new
#template = temp
end
def col(name, options = {})
columns << Column.new(name, options)
end
def show(list)
template.content_tag(:table) do
template.output_buffer << template.content_tag(:tr) do
columns.collect do |c|
template.output_buffer << content_tag(:th, c.th_value)
end
end
list.collect do |item|
template.output_buffer << template.content_tag(:tr) do
columns.collect do |c|
template.output_buffer << template.content_tag(:td, c.td_value(item))
end
end
end
end
end
end
end

Related

render partial view recursively in rails 5

I'm new to ruby on rails and I'm facing a problem rendering nested questions.
What I want to achieve is rendering the question and check if it have children question then render the children questions as well.
there is no limit on the nesting levels, so I have to use recursion method to achieve this and this is what I came up with.
# view file code
<% #questions.each do |q| %>
<%= render partial: "shared/question_block", locals: {q: q} %>
<% if have_children_questions?(q.id) == 'true' %>
<%= print_children_questions( get_children_ids(q.id) ) %>
<% end %>
<% end %>
and here is the helper functions I created
def have_children_questions?(id)
children = Question.get_children(id)
if !children.empty?
'true'
else
'false'
end
end
def get_children_ids(id)
ids = Question.where(parent: id).pluck(:id)
end
def print_children_questions(ids)
ids.each do |id|
q = Question.find(id)
render partial: "shared/question_block", locals: {q: q}
if have_children_questions?(id)
print_children_questions( get_children_ids(id) )
end
end
end
print_children_questions method returning the ids instead of the partial view, what I'm doing wrong?
is there is a better solution
Thanks in advance

Duplicating a record with associated images using Carrierwave

I have an app which you can store order/invoices in. I'm building a simple feature where you can duplicate invoices for my customers. I wrote this method in my Order.rb model which:
Takes the invoice, duplicates the associated lineitems, adds the new OrderID into them...and does the same for associated images.
def self.duplicate_it(invoice)
new_invoice = invoice.dup
new_invoice.save
invoice.lineitems.each do |l|
new_lineitem = l.dup
new_lineitem.order_id = new_invoice.id
new_lineitem.save
end
invoice.images.each do |i|
new_image = i.dup
new_image.order_id = new_invoice.id
new_image.save
end
return new_invoice
end
Unfortunately, you can't just .dup the image because there's all this associate expiration stuff since I'm storing images on S3. Is there a way to regenerate the image maybe using its image_url?
The error I get when running this is below. Which tells me not all the associated image information is dup'd correctly.
Showing /Users/bruceackerman/Dropbox/printavo/app/views/orders/_image-display.erb where line #3 raised:
undefined method `content_type' for nil:NilClass
Extracted source (around line #3):
1: <% #order.images.each do |image| %>
2: <% if image.image && image.image.file %>
3: <% if image.image.file.content_type == "application/pdf" %>
4: <%= link_to image_tag("/images/app/pdf.jpg",
5: :class => 'invoice-image'),
6: image.image_url,
i think you can do the following
invoice.images.each do |i|
new_image = new_invoice.images.new({ order_id: new_invoice.id })
new_image.image.download!(i.image_url)
new_image.store_image!
new_image.save!
end
This is actually how I did it for each lineitem on an order:
def self.duplicate_it(invoice)
new_invoice = invoice.dup :include => {:lineitems => :images} do |original, kopy|
kopy.image = original.image if kopy.is_a?(Image)
end
new_invoice.save!
return new_invoice
end
It is a bit late however this is my solution. I have had far too many problems with .download!
if #record.duplicable?
new_record = #record.dup
if new_record.save
#record.uploads.each do |upload|
new_image = new_record.uploads.new({ uploadable_id: new_record.id })
new_image.filename = Rails.root.join('public'+upload.filename_url).open
new_image.save!
end
end
Here is my upload.rb
class Upload < ActiveRecord::Base
belongs_to :uploadable, polymorphic: true
mount_uploader :filename, ImageUploader
end
Hope it helps!

Rails 3: Find parent of polymorphic model in controller?

I'm trying to find an elegant (standard) way to pass the parent of a polymorphic model on to the view. For example:
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
The following way (find_imageable) works, but it seems "hackish".
#PictureController (updated to include full listing)
class PictureController < ApplicationController
#/employees/:id/picture/new
#/products/:id/picture/new
def new
#picture = imageable.pictures.new
respond_with [imageable, #picture]
end
private
def imageable
#imageable ||= find_imageable
end
def find_imageable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Is there a better way?
EDIT
I'm doing a new action. The path takes the form of parent_model/:id/picture/new and params include the parent id (employee_id or product_id).
I'm not sure exactly what you're trying to do but if you're trying to find the object that 'owns' the picture you should be able to use the imageable_type field to get the class name. You don't even need a helper method for this, just
def show
#picture = Picture.find(params[:id])
#parent = #picture.imagable
#=> so on and so forth
end
Update
For an index action you could do
def index
#pictures = Picture.includes(:imagable).all
end
That will instantiate all 'imagables' for you.
Update II: The Wrath of Poly
For your new method you could just pass the id to your constructor, but if you want to instantiate the parent you could get it from the url like
def parent
#parent ||= %w(employee product).find {|p| request.path.split('/').include? p }
end
def parent_class
parent.classify.constantize
end
def imageable
#imageable ||= parent_class.find(params["#{parent}_id"])
end
You could of course define a constant in your controller that contained the possible parents and use that instead of listing them in the method explicitly. Using the request path object feels a little more 'Rails-y' to me.
I just ran into this same problem.
The way I 'sort of' solved it is defining a find_parent method in each model with polymorphic associations.
class Polymorphic1 < ActiveRecord::Base
belongs_to :parent1, :polymorphic => true
def find_parent
self.parent1
end
end
class Polymorphic2 < ActiveRecord::Base
belongs_to :parent2, :polymorphic => true
def find_parent
self.parent2
end
end
Unfortunately, I can not think of a better way. Hope this helps a bit for you.
This is the way I did it for multiple nested resources, where the last param is the polymorphic model we are dealing with: (only slightly different from your own)
def find_noteable
#possibilities = []
params.each do |name, value|
if name =~ /(.+)_id$/
#possibilities.push $1.classify.constantize.find(value)
end
end
return #possibilities.last
end
Then in the view, something like this:
<% # Don't think this was needed: #possibilities << picture %>
<%= link_to polymorphic_path(#possibilities.map {|p| p}) do %>
The reason for returning the last of that array is to allow finding the child/poly records in question i.e. #employee.pictures or #product.pictures

How to create own block helper with two or more nested children?

I'd like to to something nested like that in my views:
<%= helper_a do |ha| %>
Content for a
<%= ha.helper_b do |hb| %>
Content for b
<%= hb.helper_c do |hc| %>
Content for c
... and so on ...
<% end %>
<% end %>
<% end %>
To get for example this:
<tag_a>
Content for a
<tag_b class="child_of_tag_a">
Content for b
<tag_c class="nested_child_of_tag_a child_of_tag_b">
Content for c
</tag_c>
</tag_b>
</tag_a>
This means, each level has access to some information of the level above (that's why they are nested and not completely autonomous methods)
I know how to create a simple helper:
def helper_a(&block)
content = capture(&block)
content_tag :tag_a, content
end
And I know I can pass my arguments to the capture to use them in the view, so something like this to get live up the |ha| of my example
def helper_a(&block)
content = capture(OBJECT_HERE, &block)
content_tag :tag_a, content
end
But where do I define this OBJECT_HERE, especially the class for it, and how can this go on nested with multiple levels capturing each block?
I came up with a couple solutions, but I'm far from being an expert in the Rails templating system.
The first one is using an instance variable :
def helper_a(&block)
with_context(:tag_a) do
content = capture(&block)
content_tag :tag_a, content
end
end
def helper_b(&block)
with_context(:tag_b) do
content = capture(&block)
content_tag :tag_b, content
end
end
def helper_c(&block)
with_context(:tag_c) do
content = capture(&block)
content_tag :tag_c, content
end
end
def with_context(name)
#context ||= []
#context.push(name)
content = yield
#context.pop
content
end
which is used this way :
<%= helper_a do %>
Content for a
<%= helper_b do %>
Content for b
<%= helper_c do %>
Content for c
... and so on ...
<% end %>
<% end %>
<% end %>
And the other solution, which passes the context at each step :
def helper_a(context = [], &block)
context = capture(context.push(:tag_a), &block)
content_tag(:tag_a, content)
end
def helper_b(context = [], &block)
context = capture(context.push(:tag_b), &block)
content_tag(:tag_b, content)
end
def helper_c(context = [], &block)
context = capture(context.push(:tag_c), &block)
content_tag(:tag_c, content)
end
which is used this way :
<%= helper_a do |context| %>
Content for a
<%= helper_b(context) do |context| %>
Content for b
<%= helper_c(context) do |context| %>
Content for c
... and so on ...
<% end %>
<% end %>
<% end %>
But I'd really advise against using either of these solutions if all you're doing is CSS styling and/or Javascript manipulation. It really complicates the helpers, is likely to introduce bugs, etc.
Hope this helps.

Ruby on Rails - Simplifying similar methods that access different variables

I'm working on a fairly simple site that allows users to choose recipe ingredients, their quantities and then shows them nutritional info based on their recipe and a large database.
Right now, I feel like I'm repeating myself a bit. I want to be able to make this "DRY" by having one method each in the Recipe and Recipe_Ingredient model that will do the same thing only accept the right parameter, which will be the type of nutrient.
Here is the relevant code in my view that currently calls two different methods (and will call more when extended to the other nutrients):
<ul>Calories <%= #recipe.total_calories %></ul>
<ul>Fat (grams) <%= #recipe.total_fat %></ul>
In my recipe model, I have methods that iterate over each of the ingredients in the recipe:
def total_calories
recipe_ingredients.to_a.sum { |i| i.total_calories }
end
def total_fat
recipe_ingredients.to_a.sum { |i| i.total_fat }
end
In the block, we call two separate methods that actually calculate the nutrients for each individual recipe ingredient:
def total_calories
ingredient.calories*ingredient.weight1*quantity/100
end
def total_fat
ingredient.fat*ingredient.weight1*quantity/100
end
This last piece is where we reference the database of ingredients. For context, here are the relationships:
class RecipeIngredient < ActiveRecord::Base
belongs_to :ingredient
belongs_to :recipe
class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
Thanks in advance for any help.
Lev
The send method with a symbol parameter works well for that kind of DRY.
<ul>Calories <%= #recipe.total :calories %></ul>
<ul>Fat (grams) <%= #recipe.total :fat %></ul>
Recipe
def total(type)
recipe_ingredients.to_a.sum { |i| i.total type }
end
RecipeIngredient
def total(type)
ingredient.send(type) * ingredient.weight1 * quantity / 100
end
You could use meta programming to dynamically add the methods. Here is a start, you can get even more DRY than this.
class DynamicTotalMatch
attr_accessor :attribute
def initialize(method_sym)
if method_sym.to_s =~ /^total_of_(.*)$/
#attribute = $1.to_sym
end
end
def match?
#attribute != nil
end
end
Recipe
class Recipe
def self.method_missing(method_sym, *arguments, &block)
match = DynamicTotalMatch.new(method_sym)
if match.match?
define_dynamic_total(method_sym, match.attribute)
send(method_sym, arguments.first)
else
super
end
end
def self.respond_to?(method_sym, include_private = false)
if DynamicTotalMatch.new(method_sym).match?
true
else
super
end
end
protected
def self.define_dynamic_total(method, attribute)
class_eval <<-RUBY
def self.#{method}(#{attribute})
recipe_ingredients.to_a.sum { |i| i.send(attribute)
end
RUBY
end
end
RecipeIngredient
class RecipeIngredient
def self.method_missing(method_sym, *arguments, &block)
match = DynamicTotalMatch.new(method_sym)
if match.match?
define_dynamic_total(method_sym, match.attribute)
send(method_sym, arguments.first)
else
super
end
end
def self.respond_to?(method_sym, include_private = false)
if DynamicTotalMatch.new(method_sym).match?
true
else
super
end
end
protected
def self.define_dynamic_total(method, attribute)
class_eval <<-RUBY
def self.#{method}(#{attribute})
ingredient.send(attribute) * ingredient.weight1 * quantity / 100
end
RUBY
end
end
Example was copied from ActiveRecord and this page: http://technicalpickles.com/posts/using-method_missing-and-respond_to-to-create-dynamic-methods/