How do I output a multidimensional hash in ERB files? - ruby

I need some help printing the values of my hash. In my "web.rb" file I have:
class Main < Sinatra::Base
j = {}
j['Cordovan Communication'] = {:title => 'UX Lead', :className => 'cordovan', :images => ['http://placehold.it/350x150','http://placehold.it/350x150','http://placehold.it/350x150']}
j['Telia'] = {:title => 'Creative Director', :className => 'telia', :images => ['http://placehold.it/350x150','http://placehold.it/350x150','http://placehold.it/350x150','http://placehold.it/350x150']}
get '/' do
#jobs = j
erb :welcome
end
end
In "welcome.rb" I'm printing the values of the hash, but it doesn't work:
<% #jobs.each do |job| %>
<div class="row">
<div class="span12">
<h2><%=h job.title %></h2>
</div>
</div>
<% end %>
Here's my error message:
NoMethodError at / undefined method `title' for #<Array:0x10c144da0>

Think what #jobs looks like:
#jobs = {
'Cordovan Communication' => {
:title => 'UX Lead',
:className => 'cordovan',
:images => ['http://placehold.it/350x150','http://placehold.it/350x150','http://placehold.it/350x150']},
'Telia' => {
:title => 'Creative Director',
:className => 'telia',
:images => ['http://placehold.it/350x150','http://placehold.it/350x150','http://placehold.it/350x150','http://placehold.it/350x150']}
}
Then remember that each called on a hash passes a key and a value to the block, and you'll see that you have:
#jobs.each do |name, details|
# On first step, name = 'Cordovan Communication', details = {:title => 'UX Lead', ...}
end
So what you want is probably:
<% #jobs.each do |name, details| %>
<div class="row">
<div class="span12">
<h2><%=h details[:title] %></h2>
</div>
</div>
<% end %>

There's no automatic method creation for Ruby hashes, e.g., you can't call job.title, since there is no title method on Hash objects. Instead you can call job[:title].
Also note that #jobs is a hash, not an array, so you probably want to call #jobs.each_pair rather than #jobs.each. It's possible to use #jobs.each, but in this case it's not going to give you what you expect.

Related

adding event functionality to my redmine calendar using bitnami stack

I want to add, update and delete event on my redmine calendar(almost similar to a google calendar).I have installed redmine on a Bitnami stack. But I'm not able to understand the code structure as I do not have proper documentation. Is there anyone who can help me on this.
The below listed code is my calendar controller .
class CalendarsController < ApplicationController
menu_item :calendar
before_action :find_optional_project
rescue_from Query::StatementInvalid, :with => :query_statement_invalid
helper :issues
helper :projects
helper :queries
include QueriesHelper
def show
if params[:year] and params[:year].to_i > 1900
#year = params[:year].to_i
if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
#month = params[:month].to_i
end
end
#year ||= User.current.today.year
#month ||= User.current.today.month
#calendar = Redmine::Helpers::Calendar.new(Date.civil(#year, #month, 1), current_language, :month)
retrieve_query
#query.group_by = nil
#query.sort_criteria = nil
if #query.valid?
events = []
events += #query.issues(:include => [:tracker, :assigned_to, :priority],
:conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?))", #calendar.startdt, #calendar.enddt, #calendar.startdt, #calendar.enddt]
)
events += #query.versions(:conditions => ["effective_date BETWEEN ? AND ?", #calendar.startdt, #calendar.enddt])
#calendar.events = events
end
render :action => 'show', :layout => false if request.xhr?
end
end
The below is the calender_helper.rb
module CalendarsHelper
def link_to_previous_month(year, month, options={})
target_year, target_month = if month == 1
[year - 1, 12]
else
[year, month - 1]
end
name = if target_month == 12
"#{month_name(target_month)} #{target_year}"
else
"#{month_name(target_month)}"
end
# \xc2\xab(utf-8) = «
link_to_month(("\xc2\xab " + name), target_year, target_month, options)
end
def link_to_next_month(year, month, options={})
target_year, target_month = if month == 12
[year + 1, 1]
else
[year, month + 1]
end
name = if target_month == 1
"#{month_name(target_month)} #{target_year}"
else
"#{month_name(target_month)}"
end
# \xc2\xbb(utf-8) = »
link_to_month((name + " \xc2\xbb"), target_year, target_month, options)
end
def link_to_month(link_name, year, month, options={})
link_to(link_name, {:params => request.query_parameters.merge(:year => year, :month => month)}, options)
end
end
Below is the view ,show.html.erb
<h2><%= #query.new_record? ? l(:label_calendar) : #query.name %></h2>
<%= form_tag({:controller => 'calendars', :action => 'show', :project_id => #project},
:method => :get, :id => 'query_form') do %>
<%= hidden_field_tag 'set_filter', '1' %>
<fieldset id="filters" class="collapsible <%= #query.new_record? ? "" : "collapsed" %>">
<legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
<div style="<%= #query.new_record? ? "" : "display: none;" %>">
<%= render :partial => 'queries/filters', :locals => {:query => #query} %>
</div>
</fieldset>
<p style="float:right;">
<%= link_to_previous_month(#year, #month, :accesskey => accesskey(:previous)) %> | <%= link_to_next_month(#year, #month, :accesskey => accesskey(:next)) %>
</p>
<p class="buttons">
<%= label_tag('month', l(:label_month)) %>
<%= select_month(#month, :prefix => "month", :discard_type => true) %>
<%= label_tag('year', l(:label_year)) %>
<%= select_year(#year, :prefix => "year", :discard_type => true) %>
<%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %>
<%= link_to l(:button_clear), { :project_id => #project, :set_filter => 1 }, :class => 'icon icon-reload' %>
</p>
<% end %>
<%= error_messages_for 'query' %>
<% if #query.valid? %>
<%= render :partial => 'common/calendar', :locals => {:calendar => #calendar} %>
<%= call_hook(:view_calendars_show_bottom, :year => #year, :month => #month, :project => #project, :query => #query) %>
<p class="legend cal">
<span class="starting"><%= l(:text_tip_issue_begin_day) %></span>
<span class="ending"><%= l(:text_tip_issue_end_day) %></span>
<span class="starting ending"><%= l(:text_tip_issue_begin_end_day) %></span>
</p>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'issues/sidebar' %>
<% end %>
<% html_title(l(:label_calendar)) -%>
This is the only code related to calendar in routes.rb
get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar'
get '/issues/calendar', :to => 'calendars#show'
In this controller you have only show action (HTTP GET). If you want update and delete you are supposed to add methods and logic for them gere. You will also need routes in config/routes.rb.
I would also recommend you to take a look into other controllers since this one looks more like a renderer of the calendar and nothing more. I don't see create action as well (HTTP POST) which means you create the entity somewhere else and update and delete are supposed to be there as well (if they are not defined already).

Rendering a partial with locals

I've rendered a partial that also loads the Users latest post in one of the tab panels.
<div role="tabpanel" class="tab-pane" id="updates_panel">
<%= render :partial => "pages/update_panel", :locals => { :post => #user.latest_post } %>
</div>
At first the method latest_post was to display the users "Last or Latest Post".
def latest_post
posts.order(:created_at => :desc).first
end
But now I realized I need to display all the post in descending order and I cant seem to get this right.
create another method like latest_posts,
def latest_posts
posts.order(:created_at => :desc)
end
def latest_post
latest_posts.first
end
And now use this in your partal,
<%= render :partial => "pages/update_panel", :locals => { :post => #user.latest_post, :posts => #user.latest_posts } %>

How can I pass a variable from the controller to a partial?

I rendering a view partial like this.
<%= render :partial => 'resources/positions', :controller => 'resources',
:action => 'this_is_a_test',
:locals => {:id_resource => 42} %>
resources_controller.rb
def this_is_a_test
#test1 = "batman"
render :partial => 'positions'
end
_positions.html.erb
<%= #test1 %>
but the variable #test1 is empty. Do you have any idea ?
def this_is_a_test
render :partial => 'positions', :locals => { :test1 => "batman" }
end
and change _position.html.erb to
<%= test1 %>

How to write a custom SimpleForm Builder to replace <INPUT> by <P>?

Extract of my Gemfile:
gem 'rails', '3.0.3'
gem 'inherited_resources', '1.2.1'
gem 'simple_form', '1.4.0'
For any resource, I have 1 view for the 3 actions (new, edit & show). Example:
<h1><%= I18n.t('admin.form.'+action_name.downcase, :name => controller_friendly_name) %></h1>
<%= simple_form_for([:admin, resource]) do |f| %>
<%= render "admin/shared/errors" %>
<%= f.input :title,
:label => "Title",
:hint => I18n.t('admin.form.input.title.hint', :name => controller_friendly_name),
:required => true,
:error => false,
:input_html => { :class => :large, :placeholder => I18n.t('admin.form.input.title.placeholder', :name => controller_friendly_name) }
%>
<%= f.input :is_visible,
:as => :radio,
:label => "Visible",
:error => false,
:required => true,
:collection => [['Yes', true], ['No', false]],
:wrapper_class => 'checkboxes-and-radiobuttons',
:checked => true
%>
<%= render "admin/shared/validation", :f => f %>
<% end %>
<% init_javascript "MyApplication.Form.disable();" if [:show].include?(action_name.to_sym) %>
See how the #show action set all the fields to disabled ? This is ugly.
Consider I can't refactor the views to have a show.html.erb file.
What I want to do:
When the action is #show, the simple_form builder use a custom builder wich replace <input>, <textarea>, <select> by <p> html tag, with the value.
Furthermore, I will customise the radiobuttons, checkboxes to.
My first step:
# app/inputs/showvalue_input.rb
class ShowvalueInput < SimpleForm::Inputs::Base
def input
# how to change 'text_field' by <p> container ?
#builder.text_field(attribute_name, input_html_options)
end
end
Can't find the way to do it. Custom Form Builders or Custom Inputs (with monkey patching) ?
Thank for the help !
Here's my solution
in my application_helper.rb:
def set_show_method_to_builder(builder)
builder.instance_eval <<-EVAL
def show?
#{action_name == "show"}
end
EVAL
end
In my forms (in the simple_form block):
<%- set_show_method_to_builder(f) -%>
And finally, in #app/inputs/string_input.rb:
class StringInput < SimpleForm::Inputs::StringInput
def input
if #builder.show?
content_tag(:p, #builder.object[attribute_name], :class => :show)
else
super
end
end
end
There's some problem with data types not mapped, but it's another story:
Can't create Custom inputs for some (Text, Booleans, ...) types, with SimpleForm

How do I add validation to a partial in Rails 3?

This is the error I am getting:
ArgumentError in Home#index
Showing /app/views/clients/_form.html.erb where line #6 raised:
You need to supply at least one validation
Extracted source (around line #6):
3: render :partial => "clients/form",
4: :locals => {:client => client}
5: -%>
6: <% client ||= Client.new
7: new_client = client.new_record? %>
8: <%= form_for(client, :html => { :class=>"ajax-form", :id => "client-ajax-form"}, :remote => true, :disable_with => (new_client ? "Adding..." : "Saving...")) do |f| %>
9: <div class="validation-error" style="display:none"></div>
My client model looks like this:
class Client < ActiveRecord::Base
# the user model for the client
belongs_to :user
has_many :projects, :order => 'created_at DESC', :dependent => :destroy
#The following produces the designers for a particular client.
#Get them from the relations where the current user is a client.
has_one :ownership, :dependent => :destroy
has_one :designer, :through => :ownership
validates :name, :presence => true,
:length => {:minimum => 1, :maximum => 128}
validates :number_of_clients
def number_of_clients
Authorization.current_user.clients.count <= Authorization.current_user.plan.num_of_clients
end
end
This is how the app/views/client/_form.html.erb partial looks:
<%#
Edit a single client
render :partial => "clients/form",
:locals => {:client => client}
-%>
<% client ||= Client.new
new_client = client.new_record? %>
<%= form_for(client, :html => { :class=>"ajax-form", :id => "client-ajax-form"}, :remote => true, :disable_with => (new_client ? "Adding..." : "Saving...")) do |f| %>
<div class="validation-error" style="display:none"></div>
<div>
<label for="client_name"><span class="icon name-icon"> </span></label>
<input type="text" class="name" size="20" name="client[name]" id="client_name" value="<%= client.name %>" > <%= f.submit(new_client ? "Add" : "Save", :class=> "green awesome")%>
</div>
<% end %>
<% content_for(:deferred_js) do %>
// From the Client Form
$('#client-ajax-form')
.bind("ajax:success", function(evt, data, status, xhr){
console.log("Calling Step View");
compv.updateStepView('client', xhr);
});
<% end %>
How do I fix that error ?
The problem is caused by the following line in your model:
validates :number_of_clients
When you use validates (s in the end) you have to follow the default rails validations like you did with the name validation. However, when you use a custom method to do the validation, you should use validate instead. So this should work:
validate :number_of_clients

Resources