I've got a presenter which I would like to make the each_with_index method available in. I've added include Enumerable in my base presenter however, I'm still getting a no method error. My current code is below:
index.erb
<% #bids.each_with_index do |bid, index| %>
<% present bid do |bid_presenter| %>
<div class="large-4 medium-4 columns <%= bid_presenter.last_column %>"></div>
<% end %>
<% end %>
bid_presenter.rb
class BidPresenter < BasePresenter
presents :bid
def last_column
if index == bid.size - 1
'end'
end
end
end
base_presenter.rb
class BasePresenter
include Enumerable
def initialize(object, template)
#object = object
#template = template
end
private
def self.presents(name)
define_method(name) do
#object
end
end
# h method returns the template object
def h
#template
end
# if h is missing fallback to template
def method_missing(*args, &block)
#template.send(*args, &block)
end
end
bids_controller.erb
# GET /bids
# GET /bids.json
def index
#bids = current_user.bids
end
You are forwarding all not explicitly implemented methods to #template. Whatever #template is doesn't seem to properly implement each. You need to make #template respond properly to each.
Related
I am trying to access my dirts/index page, but I am getting this error shown in the picture below.
So I put a byebug in the #total_trip_miles to see what is going on:
class Driver < ApplicationRecord
has_many :dirts
validates :name, presence: true, uniqueness: true
def total_trip_miles
byebug
collect_trip_miles.round.to_s
end
def average_speed
total_distance = collect_trip_miles
total_rate = collect_trip_seconds
((total_distance/total_rate)*3600).round
end
def collect_trip_miles
dirts.map do |trip|
trip.distance.to_f
end.inject(:+)
end
def collect_trip_seconds
seconds = []
dirts.map do |trip|
seconds << trip.change_in_time(trip.start_time, trip.end_time)
end
seconds.inject(:+)
end
end
When I call the collect_trip_miles.round.to_s from byebug I get "55", which is exactly what I want to pass my spec:
I call the method from #drivers in the dirt/index.html.erb:
<ul id="trips">
<% drivers.each do |driver| %>
<li>
<article class="driver">
<header>
<h2><%= show_name_of(driver) %></h2>
</header>
<p>
<%= "#{show_total_miles_of(driver)} Miles" %>
</p>
<table>
</table>
<footer>
</footer>
</article>
</li>
<% end %>
</ul>
And those methods are called from my app/helpers/dirts_helper.rb
module DirtsHelper
def show_name_of(driver)
the_driver(driver).name.capitalize
end
def show_total_miles_of(driver)
the_driver(driver).total_trip_miles
end
def the_driver(driver)
Driver.find(driver.first)
end
def drivers
#driver_store = {}
#drivers.each_with_index do |driver, dirts|
#driver_store[driver.id] = driver.dirts
end
#driver_store
end
end
And then the controller action comes from app/controllers/dirts_controller.rb
class DirtsController < ApplicationController
def index
#drivers = Driver.all
end
end
Based on what I've described and shown evidence for, is there some-super-obvious-I-should-be-ashamed-of-myself reason why my driver model's methods are blowing up in my localhost but debugging is reporting as expected?
Could it be this?
def the_driver(driver)
Driver.find(driver.first)
end
You are iterating drivers.each do |driver| in your view, do when you pass it into show_total_miles_of and then subsequently the_driver, you should not have to find it, as you are already dealing with a single instance of an object.
I made the mistake of not guarding against nil in my collection of drivers, some of them don't have any trip miles. So, calling #round on nothing is throwing an error but it works in ByeBug because that is just capturing one item in the collection that just so happens to have miles as well and so calling #round on the Float works.
I'm new on rails and I have a book to study them. In one practice, I created a helper in my Application Helper, the test from RSpec work fine, until I have to print the result of my helper. No show any result and no error happens.
application_helper.rb
module ApplicationHelper
def title(*parts)
unless parts.empty?
content_for :title do
(parts << "Ticketee").join(" - ")
end
end
end
end
show.html.erb
<% title(#project.name) %>
projects_controller.rb
class ProjectsController < ApplicationController
def show
#project = Project.find(params[:id])
end
end
and when I go to the show link I supposed to see "Random Project name - Ticketee", however only they show me "Ticketee".
Any help...
<% title(#project.name) %>
Means don't show to the user
<%= title(#project.name) %>
Means show to the user - notice the equals.
I am trying to generalize few methods that will be used by multiple models/views/controllers but i'm having no luck. Here is the original code that works when it is just for 1 set called Trucks.
View
<h2>Trucks</h2>
<%= form_tag trucks_path, :method => 'get' do %>
<%= hidden_field_tag :direction, params[:direction] %>
<%= hidden_field_tag :sort, params[:sort] %>
<p>
Search:
<%= text_field_tag :search %>
by
<%= select_tag :search_column, options_for_select(Truck.translated_searchable_columns(['attribute1']), params[:search_column]) %>
<%= submit_tag "Search" %>
</p>
<% end %>
<!-- Display code goes here, but im not showing since its just a table -->
Controller
def index
#trucks = Truck.search(params[:search], params[:search_column]).order(sort_column(Truck, "truck_no") + " " + sort_direction)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #trucks }
end
end
Model
class Truck < ActiveRecord::Base
attr_accessible :attribute1, :attribute2, :attribute3
def self.search(keyword, column_name)
if self.column_names.include?(column_name.to_s)
where("trucks.#{column_name} LIKE ?", "%#{keyword}%")
else
scoped
end
end
def self.searchable_columns(unwanted_columns)
self.column_names.reject{ |column| unwanted_columns.include?(column) }
end
def self.translated_searchable_columns(unwanted_columns)
columns = self.searchable_columns(unwanted_columns)
result = columns.map{ |column| [Truck.human_attribute_name(column.to_sym), column] }
result
end
end
All this works without a hitch, now I can't figure out for the life of me how to move these methods to lib and have them generalized so that lets say Trailers is able to call in the same method and pass in its information and achieve the same result. I am trying to make this code DRY as possible. Could anyone explain me what I need to do to achieve this? How does lib access the database?
The concept you're looking for is called a "concern". Rails has a convenience module for implementing concerns called ActiveSupport::Concern. Here's how you might extract your model methods:
module Searchable
extend ActiveSupport::Concern
module ClassMethods
def search(keyword, column_name)
if column_names.include?(column_name.to_s)
where("#{table_name}.#{column_name} LIKE ?", "%#{keyword}%")
else
scoped
end
end
def searchable_columns(unwanted_columns)
column_names.reject{ |column| unwanted_columns.include?(column) }
end
def translated_searchable_columns(unwanted_columns)
columns = searchable_columns(unwanted_columns)
columns.map{ |column| [human_attribute_name(column.to_sym), column] }
end
end
end
And then in your model:
class Truck < ActiveRecord::Base
include Searchable
attr_accessible :attribute1, :attribute2, :attribute3
end
As for where exactly you should store the Searchable module, it's up to you -- it just has to be someplace that's included in config.autoload_paths, just like a model or controller. Rails 4 introduced a convention that model concerns are stored in app/models/concerns, and controller concerns in app/controllers/concerns, but there is nothing special about these locations other than being autoloaded by default.
Basically, I have a class that outputs some html:
class Foo
include ActionView::Helpers
def initialize(stuff)
#stuff = stuff
end
def bar
content_tag :p, #stuff
end
end
so I can do: Foo.new(123).bar
and get "<p>123</p>"
... But what I really want to do is something like this:
class Foo << ActionView::Base
def initialize(stuff)
#stuff = stuff
end
def bar
render :template => "#{Rails.root/views/foo/omg.html.erb}"
end
end
# views/omg.html.erb
<h1>Wow, stuff is <%= #stuff %></h1>
and then do Foo.new(456).bar and get "<h1>Wow, stuff is 456</h1>"
Just call erb directly? Something like:
def bar
template = ERB.new(File.read("#{Rails.root}/views/foo/omg.html.erb"))
template.result(binding)
end
I am making a view helper to render set of data in a format. I made these classes
require 'app/data_list/helper'
module App
module DataList
autoload :Builder, 'app/data_list/builder'
##data_list_tag = :ol
##list_tag = :ul
end
end
ActionView::Base.send :include, App::DataList::Helper
helper is
module App
module DataList
module Helper
def data_list_for(object, html_options={}, &block)
builder = App::DataList::Builder
arr_content = []
object.each do |o|
arr_content << capture(builder.new(o, self), &block)
end
content_tag(:ol, arr_content.join(" ").html_safe, html_options).html_safe
end
end
end
end
builder is
require 'app/data_list/column'
module App
module DataList
class Builder
include App::DataList::Column
include ActionView::Helpers::TagHelper
include ActionView::Helpers::AssetTagHelper
attr_reader :object, :template
def initialize(object, template)
#object, #template = object, template
end
protected
def wrap_list_item(name, value, options, &block)
content_tag(:li, value).html_safe
end
end
end
end
column module is
module App
module DataList
module Column
def column(attribute_name, options={}, &block)
collection_block, block = block, nil if block_given?
puts attribute_name
value = if block
block
elsif #object.respond_to?(:"human_#{attribute_name}")
#object.send :"human_#{attribute_name}"
else
#object.send(attribute_name)
end
wrap_list_item(attribute_name, value, options, &collection_block)
end
end
end
end
Now i write code to test it
<%= data_list_for #contracts do |l| %>
<%= l.column :age %>
<%= l.column :contact do |c| %>
<%= c.column :phones %>
<% end %>
<%= l.column :company %>
<% end %>
Every thing is working fine , age , contact , company is working fine. But phones for the contact is not showing.
Does any one have an idea, i know i have missed something in the code. Looking for your help.
Updated question with complete source is enter link description here
There are two issues I can see in the column module.
1) If a block is provided you're setting it to nil - so if block is always returning false. 2) Even if block wasn't nil you're just returning the block as the value, not actually passing control to the block. You should be calling block.call or yielding. Implicit blocks execute faster, so I think your column module should look more like this:
module DataList
module Column
def column(attribute_name, options={})
value = begin
if block_given?
yield self.class.new(#object.send(attribute_name), #template)
elsif #object.respond_to?(:"human_#{attribute_name}")
#object.send :"human_#{attribute_name}"
else
#object.send(attribute_name)
end
end
wrap_list_item(attribute_name, value, options)
end
end
end
The solution is now posted in the discussion.