I wrote a simple helper for my rails application:
def calendar_build
5.times do
whole_cal
end
end
def whole_cal
content_tag(:div, :class => "row") do
small_cal + big_cal
end
end
def small_cal
content_tag(:div, :class => "col-xs-2 token-text") do
concat(content_tag(:p, "15.20"))
end
end
def big_cal
content_tag(:div, :class => "col-xs-10 weite_cal") do
concat(content_tag(:input,"", class: "form-control input-sm pa"))
end
end
How you can see i try to generate 5 whole_cal:
def calendar_build
5.times do
whole_cal
end
end
But in my view this only displays 5 why? Thanks
The return value of the loop is 5.
1.9.3p194 :056 > 5.times {}
=> 5
You should probably do
def calendar_build
whole_cals = []
5.times do
whole_cals << whole_cal
end
whole_cals
end
And iterate the array in your view
Couldn't you do whole_cal*5? String multiplication works in general.
You have to add the generated html code to a variable like result, then put result as last line in your method to return the concatenated code
something like:
result = ""
5.times do
result += html code
end
result
and depending on your html code, you should replace the last line with result.html_safe
Related
as in title I'm trying to create helper that does that but I'm struggling. I'm getting errors or simply empty list like this:
And I want to achieve this:
There is to much logic to simply put this code in view. A results is a hash where the key is a website id and value is either an array of bookmarks ids or just bookmark id.
My code:
module WebsitesHelper
def present_search_results(results)
content_tag(:ul, class: "websites-list") do
results.each do |key, value|
website = Website.find(key)
concat(content_tag(:li, website.url, class: "website-#{key}") do
bookmarks = website.bookmarks.select do |b|
if value.is_a?(Array)
value.include?(b.id)
else
value = b.id
end
end
content_tag(:ul, nil, id: "website-#{key}") do
bookmarks.each do |b|
content_tag(:li, b.title)
end
end
end)
end
end
end
end
If you want to stick with helpers, then something like this could help:
def present_search_results(results)
content_tag(:ul, class: "websites-list") do
results.map do |website_id, bookmarks|
bookmarks = [bookmarks] unless bookmarks.is_a?(Array)
content_tag(:li, class: "website-#{website_id}") do
website = Website.find(website_id)
concat(website.url)
concat(
content_tag(:ul, class: "bookmarks-list") do
bookmarks.map do |bookmark_id|
bookmark = Bookmark.find(bookmark_id)
content_tag(:li, bookmark.title)
end.reduce(:+)
end
)
end
end.reduce(:+)
end
end
But, in my opinion, that code is not easy to read, so you could use plain html instead, like this:
def present_search_results(results)
list = "<ul class='websites-list'>"
results.each do |(website_id, bookmarks)|
bookmarks = [bookmarks] unless bookmarks.is_a?(Array)
website = Website.find(website_id)
list += "<li class='website-#{website_id}'>#{website}"
list += "<ul class='bookmarks-list'>"
bookmarks.each do |bookmark_id|
bookmark = Bookmark.find(bookmark_id)
list += "<li>#{bookmark.title}</li>"
end
list += "</ul></li>"
end
list += "</ul>"
list.html_safe
end
I like this one better, since it is easier to read. But both with output the list you want.
I have my custom presenter
class ShiftPresenter
def initialize(shift, template)
#shift = shift
#template = template
end
def h
#template
end
def users_list
logs = ShiftLog.by_shift(#shift)
names = logs.map do |log|
log.cardiologist.name
end
h.content_tag :div, names unless names.empty?
end
end
and #index view
- present shift do |shift_presenter|
= shift_presenter.user_list
How to present users names using li instead of ['tom', 'jerry']
You can add this to your presenter method:
def users_list
logs = ShiftLog.by_shift(#shift)
names = logs.map(&:cardiologist).map(&:name)#.compact.uniq # you can add this if you want
h.content_tag :div do
h.content_tag :ul do
ul_content = ''.html_safe
names.each do |name|
ul_content << h.content_tag :li, name
end
ul_content
end
end
The thing is it works as block with the return statement: the last used/returned object will be put inside the content_tag.
Try to wrap each element of names in users_list method into <li> tag and join them in a string. To do this you need to change this line:
h.content_tag :div, names unless names.empty?
into this:
h.content_tag :div, names.map{|str| '<li>' + str + '</li>'}.join unless names.empty?
I'm new in ruby on rails. I'm trying to call a class from a collection_action in ActiveAdmin. Here is the code(app/admin/models):
collection_action :status_race, :method => :post do
#Do some import work..
redirect_to :class => :import_route
end
And this is the code of the class I want to call(app/lib/route):
class ImportRoute
def initialize
#seperator = " "
#time_format = "%d-%m-%y"
end
def run(filename)
puts "Running route import file"
raise "File" + filename + "doesn't not exist" unless File.exist(filename)
ri = RouteImporter.find(:name => self.class.name)
if(ri.nil?)
puts "Error, file doesn't exists"
end
CSV.foreach(filename, {:col_sep => #seperator}) do |row|
if row.lenght >5
ri.country_name = row[0] + " " + row[1]
ri.type = row[2]
ri.company = row [3]
else
ri.country_name = row[0]
ri.type = row[1]
ri.company = row[2]
ri.date = row[4].gsub(";", " ")
end
end
end
end
I was using redirect_to to call the class but is not working, and I don't have any clue about how to do it. Any idea? Thanks!
This code is taken from http://activeadmin.info/docs/8-custom-actions.html#collection_actions
ActiveAdmin.register Post do
collection_action :import_csv, :method => :post do
# Do some CSV importing work here...
redirect_to {:action => :index}, :notice => "CSV imported successfully!"
end
end
This collection action will generate a route at
“/admin/posts/import_csv” pointing to the
Admin::PostsController#import_csv controller action.
So it means you have to add a method import_csv in app/controllers/admin/posts_controller.rb. Inside this method, you can instantiate your model:
def import_csv
import_route = ImportRoute.new
# do stuff on this object
end
You can easily adapt this to your code
I have notes attribute in Product model with text "something, something else".
In views I wanted see:
<div>
<span>Something</span>
<span>Something else</span>
</div>
Also I have working code, but I want refactor with decorator(draper) or maybe use helpers.
%div
- product.notes.split(/,/).each do |e|
%span= e.strip.capitalize
In decorator:
def notes_list
model.notes.split(/,/).each do |e|
h.content_tag(:span, e.strip.capitalize)
end
end
In views:
%div
= product.notes_list
(or analog in helpers:
def notes_list(product)
product.notes.split(/,/).each do |element|
content_tag(:span, element.strip.capitalize)
end
end
call:
%div
= notes_list(product)
)
But this returns
<div>
"
["something", " something else"]
"
</div>
What is wrong?
your notes_list is returning product.notes.split(/,/)
Try
def notes_list(product)
result = product.notes.split(/,/).inject([]) do |result, element|
result << content_tag(:span, element.strip.mb_chars.capitalize)
end
result.join("\n")
end
I'm developing an application that displays tabular data in many different areas and I find myself constantly using the same HTML table structure over and over. For example a particular table looks like this:
%table.zebra-striped#user-table{ :cellspacing => "0" }
%colgroup
%col{:id => "email"}
%col{:id => "username"}
%col{:id => "sign-in-count"}
%col{:id => "last-sign-in-at"}
%thead
%tr
%th{:id => "email-head", :scope => "col"} E-mail
%th{:id => "username-head", :scope => "col"} Username
%th{:id => "sign-in-count-head", :scope => "col"} Sign Ins
%th{:id => "last-sign-in-at-head", :scope => "col"} Last Sign In
%tbody
- #users.each do |user|
%tr{ :class => zebra }
%td
=h user.email
%td
=h user.username
%td
=h user.sign_in_count
%td
=h user.last_sign_in_at
Ideally, I would like to create some kind of helper method where I could do something like:
= custom_table_for #users do
= column :email
= column :username do |user|
= link_to user.username, user_path(user)
= column "Sign Ins", :sign_in_count
= column :last_sign_in_at
This way I can change the formatting of the data in the columns and the column header names if I'm not happy with default values, but have the table generated for me.
I suppose I could create a normal helper, but I'd have to use arrays and I have no idea how I could include custom data formatting per column.
active_admin has something similar to this which you can see here: http://activeadmin.info/docs/3-index-pages/index-as-table.html
Any leads or ideas would be greatly appreciated.
I just came up with this:
A few points:
The line #columns = [] is a reset so you can call it more than once.
The yield in the custom_table_for calls the block that you pass it.
The block in the column method is stored and called in custom_table_for if it is set.
I included a sample class to show the usage too.
please note I did this outside of a rails app and you almost certainly want to use http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag instead of the p "<table>" this is merely for sample purposes when you run it in the console.
module TableHelper
def custom_table_for(items)
#columns = []
yield
p "<table>"
#columns.each do |c|
p "<th>#{c[:value]}</th>"
end
items.each do |e|
p "<tr>"
#columns.each do |c|
e[c[:name]] = c[:block].call(e[c[:name]]) if c[:block]
p "<td>#{e[c[:name]]}</td>"
end
p "</tr>"
end
p "</table>"
end
def column(name, value = nil, &block)
value = name unless value
#columns << {:name => name, :value => value, :block => block}
end
end
class ExampleTable
include TableHelper
def test
#users = [{:email => "Email 1", :username => "Test User"}, {:email => "Email 2", :username => "Test User 2"}]
custom_table_for #users do
column :email, "Email"
column :username do |user|
user.upcase
end
end
end
end
et = ExampleTable.new
et.test
UPDATE
I migrated this to rails to use content_tags
module TableHelper
def custom_table_for(items)
#columns = []
yield
content_tag :table do
thead + tbody(items)
end
end
def thead
content_tag :thead do
content_tag :tr do
#columns.each do |c|
concat(content_tag(:th, c[:value]))
end
end
end
end
def tbody(items)
content_tag :tbody do
items.each { |e|
concat(content_tag(:tr){
#columns.each { |c|
e[c[:name]] = c[:block].call(e[c[:name]]) if c[:block]
concat(content_tag(:td, e[c[:name]]))
}
})
}
end
end
def column(name, value = nil, &block)
value = name unless value
#columns << {:name => name, :value => value, :block => block}
end
end
To compliment #gazler's response, here's a way to make a table of a single resource-- column one for attribute names, column two for their values:
module TableHelper
#resource = nil
def simple_table_for(resource)
#resource = resource
content_tag :table do
content_tag :tbody do
yield
end
end
end
def row(key, label = nil, &block)
if key.is_a? String
label = key
end
content_tag(:tr) {
concat content_tag :td, label || key.capitalize
concat content_tag(:td ){
if block_given?
yield
else
#resource.send(key)
end
}
}
end
end