I have simple select list to mark whether a building is for sale or not:
<%= select(:building, :for_sale, options_for_select([['Unknown', 'u'], ['Yes', 'y'], ['No', 'n']])) %>
This is in a New view. It will store for example 'u' when the user selects "Unknown".
However, when the record is created I am directed to the Show view where I see 'u' instead of "Unknown" which is what I would like to see (although I want to store 'u').
What is an efficient way of displaying the user (or Human) text? Maybe it is just a helper method but anything I have come up with seems to be a lot of code for something so simple. Any "The Rails Way" approaches to this?
UPDATE: I am currently doing this in my view:
<% case #building.for_sale when 'u' %>
Unknown
<% when 'y'%>
Yes
<% when 'n'%>
No
<% end %>
But this seems... well, dumb.
So, question still remains. Is there a best methods way of dealing with this scenario?
I usually use the I18n API to do this.
I store every constant under a key in the config/locales/LOCALE.yml:
en:
constants:
u: "Unknown"
y: "Yes"
n: "No"
Use a helper to retrieve the constants translation:
def translate_constant(constant)
t("constants.#{constant}")
end
# Usage
translate_constant(#building.for_sale)
You could also create a helper to create the select options:
def constant_options_for_select(options)
options_for_select(options.map {|option| [translate_constant(option), option] })
end
# Usage
constant_options_for_select(['u', 'y', 'n'])
Related
Requesting expert help.
I have an applications table which has_many metrics.
At some point of time, metrics will have following kind of records.
{capture_time:"08:00:10.1234",metric_name:"log",metric_value:"OK",application_id:1}
{capture_time:"09:00:10.1234",metric_name:"process",metric_value:"KO",application_id:1}
{capture_time:"10:00:10.1234",metric_name:"process",metric_value:"OK",application_id:1}
{capture_time:"08:00:10.1234",metric_name:"log",metric_value:"OK",application_id:2}
{capture_time:"09:00:10.1234",metric_name:"process",metric_value:"OK",application_id:2}
{capture_time:"10:00:10.1234",metric_name:"process",metric_value:"KO",application_id:2}
I have a bigger loop for applications and for each application , I create buttons for each metric for that application
<% applic.metric.uniq{|p|p.metric_name}.each do |m| %>
<%= link_to m.metric_name, metrics_path(m.application_id,metric_name: m.metric_name) , :class=>"btn btn-success",:role=>"button" %>
<% end %>
On clicking any button it shows me records only for that metrics. For e.g. if I click on process, i see all records of that metric, which is 2 records in my case.
So till here its fine. What I am looking help for is two folds:
How to determine latest metrics(based in capture time) for that application that is KO and then use that to change the class in link_to inside the loop. Something like this:
<% applic.metric.uniq{|p|p.metric_name}.each do |m| %>
<%= link_to m.metric_name, metrics_path(m.application_id,metric_name: m.metric_name),:class=>"btn btn-success",:role=>"button" %>
<% end %>
Class => btn-danger if latest record for this metric was KO else btn-success
Then I would want to use the combined statuses of the Metrices and change the Class for the whole Application1 box.
For e.g if any one of Process, Log, Errorcounts is failed , which means any of the latest matrices of any of 3 category is KO, then the whole Application1 box should have a class as "btn-danger"
like this:
UPDATE 1 : Many Thanks to #sammms
I tried the suggestion and created following, but it still does not solve my problem.
class Metric < ApplicationRecord
belongs_to :application
def isFailed(metric_value=nil)
metric_value == 'KO'
end
end
<% applic.metric.uniq{|p|p.metric_name}.each do |metric| %>
<%= link_to metric.metric_name, application_dashboard_metrics_path(appid:metric.application_id,metric_name: metric.metric_name),
{:class=>"btn #{metric.isFailed(metric.metric_value)? 'btn-danger':'btn-success' }",:role=>"button"} %>
<% end %>
the string interpolation works, as in it changes the class based on metric value. But the problem is in uniq bit here.
applic.metric.uniq{|p|p.metric_name}.each
since I am looping through only the unique metric_name, it could be the one with metric_value as OK. And hence when it loops, it actually does not find any KO for that metric.
If I don't use uniq in the loop, then I see one button for each record. something like below,
This is not what I wanted.
I wanted to have a button only once, per metric_name, then change the class based on the collective status of all the records for that metric.
So, when I have 100 record for process metric, I don't want 100 buttons, I want only one process button, but the class should be based on if the latest metric_value is KO.
UPDATE 2:
I solved the problem with this:
def isFailed(metric_name=nil)
p metric_name
#metric_value == 'KO'
Metric.where(metric_name:metric_name).order("capture_time DESC").first.metric_value == "KO"
end
Now I need to figure out the part 2.
Since you are inside of an ERB block <%=... %> you can write vanilla ruby and it will be evaluated. That means you can used interpolation inside the string you pass to class, e.g.
class="#{'btn-danger' if metric.ko?}"
where ko? is a method defined in Metric that will return the boolean used to evaluate your condition. eg...
class Metric
def ko?
metric_value == 'KO'
end
end
For the second part, you could use the same logic. Create a CSS class that makes your box look the way you want it to look, then conditionally add it using string interpolation in the ERB class definition. Then just define a method on the Class (I think it sounds like you would want the application class in this case so you can evaluate it's associated metrics) and use that to return a boolean.
In my app I am trying to incorporate better fragment caching.
Is it a best practice to do call fragments like this:
<% cache("user/#{current_user.id}/info") do %>
<%= current_user.email %> information goes here
<% end %>
Yes you are doing it right!
Why?
The cache fragment's key must reflect the "uniqueness" of the content:
Statement: Your content is uniq for each user
Conclusion: Your fragment's key must be different for each user
Usage: using the user's id is the best choice since every user id is uniq!
Is there any standard or emerging standard to document the parameters that can be passed into a Rails partial ?
When _my_partial.html.erb expects a title and an elements local var passed with render 'my_partial', title: t, elements: e, there must be a common way to document their names, expected types and roles, without reading the whole partial code. Something like RDoc or Tomdoc for methods and classes. Isn't there ?
Edit: I've found a post whose author advocates initializing parameters with <% var ||= 'default_val' %> in the first lines of the partial, which is indeed a safe practice and a kind of in-code doc. Is there really no comment/parameter-declaration solution for this ?
At the beginning of your partial, simply call all the variables that are referenced.
# _my_partial.html.erb
<% title %> <--- first line of file
<% elements[0] %>
<h3><%= title %></h3>
<% elements.each do |element| %>
<p> etc ... </p>
Reasons why this is good for your project:
it does not rely on comments or non-code files
any developer on the project can quickly find out which variables are needed by looking at the top of the file in question
by calling the variables, you ensure that a missing variable will result in an exception.
elements is called with square brackets because we also want it to blow up if it's not an enumerable, right?
The practice of using <% var ||= 'default_val' %> is actually unsafe because it allows bugs to hide. You want your code to immediately blow up the moment something isn't done right. And if these variables should be passed, then you want the code to blow up when they're not there.
I'm trying to build a condition based on wether or not a "user" is a "member". Basically I need a way of checking if the current_user.id matches any of the user_id of any members. The non-working code I have right now is:
<% if current_user = #page.members %>
you can view this content.
<% end %>
I'm looking for something along the lines of: "If current_user.id exists in the "user_id" of any members."
Something like this, based on the field names in your question:
<% if #page.members.map(&:user_id).include? current_user.id %>
You can view this content
<% end %>
Assuming your #page.members variable contains an array, you can use the include? method:
<% if #page.members.include? current_user %>
you can view this content.
<% end %>
If you're using an array of ids, you will of course need to change the test slightly to look for the current user's id:
<% if #page.members.include? current_user.id %>
you can view this content.
<% end %>
#member_ids = #page.members.map{|m| m.id()}
then check for the condition as below
#memeber_ids.include? current_user.id()
Has said before include? should do the thing.
I'm just answering to tell you about a gem called CanCan, that gives you easy access for authorization "helpers".
Why you should use CanCan instead of doing what you are actually doing?
Don't reinventing the weel most of the times it's a goob practice.
You are placing business logic on the view (bad practice).
CanCan most likely has been developed thinking on security, and all the best practices in mind.
You save some developing hours.
Sorry if I repeated myself.
I have the following code in a layout:
Posted <%=time_ago_in_words post.created_at %> ago
<% if post.has_tag != nil %>
in the <%= post.get_first_tag.name %> category
<% end %>
And the following code in the post model which is inheriting form ActiveRecord::Base
def has_tag
!self.tags.empty?
end
def get_first_tag
self.tags[0]
end
Tags is also inherited from ActiveRecord::Base and Post 'has_many' Tags
Firstly: Is this the best way of checking if the post object has at least 1 associate tag attribute.
Secondly: Should I be putting this logic into a helper method?
Thirdly: Why doesn't the following work (it returns a # where the tags should be):
in the <%= post.tags.to_sentence %> category,
I guess its because tags aren't actually stored as an array attribute, but i don't really know.
This is a perfectly good way of checking if there are tags or not. However, self.tags.empty? will return true or false so post.has_tag will never be nil.
It's worth noting that, in ruby, it is common to name methods that return true or false with a question mark. So post.has_tag? would be a better name for your method (like the empty? method for the tags).
This sort of method belongs in the model class rather than a helper as it is not specific to the view layer; you might want to call this method from other model classes, for example.
The reason you are getting # instead of your tag names is that you are trying to convert a collection of tags to a sentence and you need instead to convert the names of the tags to a sentence. You should be able to do
post.tags.map(&:name).to_sentence
which will take the names of the tags and turn them into a sentence.
For one thing, you probably need
<% if post.has_tag %>
instead of
<% if post.has_tag != nil %>
In your definition, has_tag should never return nil, and thus 'in the...' part will always be shown.
Generally, your idea seems fine to me: I often add helpers like these to models.