I am trying to add a link to a blog_post using in this case blog.link
If for example myblog.link = new_contact_path, it would be "new_contact_path".
In my view I am trying to create a link using
<%= #blogs.each do |blog| %>
<%= link_to blog.title, blog.link %>
<%end %>
I tried using #{blog.link} but that does not work.
I ended up trying something else. I will post it in the answer.
You cannot convert a string to a variable, for the simple reason that variables aren't objects in Ruby. If you wanted to convert a string to a variable, you would do that by either calling a method on the string, or by calling a method on some other object as passing the string as an argument. Either way, the variable would have to be returned by the method, but methods can only return objects and variables aren't objects.
Based on your case I guess you should use Object#send or Object#public_send methods:
'qwe'.send('upcase') # => "QWE"
What I did instead was made a helper method.
def blog_action_link(link)
case link
when "person"
new_person_path
when "place"
places_path
else
new_contact_path
end
end
Then I used the helper in my view instead.
Related
I have the following code
if admin_authorized?
#allschools = School.all
elsif faculty_authorized?
#allschools = School.get(Faculty.get(session[:faculty_id]))
end
I am getting this error
undefined method `each' for #<School:0x007f88a1360318>
#allschools will either be an array of schools or a singleton school. I need to iterate over this list in the view, like so:
<% #allschools.each do |s| %>
<%= f_optionselected(s.id.to_s, params[:school], s.name) %>
<% end %>
I've tried to do if statements with #allschools.count, #allschools.typeof(Array), ....
Should I use two different variables and a PHP type isset() statment to determine which block to display? Or is there a way to iterate over the statement in some Ruby way?
School.all returns an ActiveRecord::Relation and you can iterate through it, as you do with each. I think School.get returns a single School instance, right? Try to wrap it into an Array:
#allschools = [School.get(Faculty.get(session[:faculty_id]))]
I'm trying to loop through and array and have checked to make sure it is being passed correctly to the template, yet am hitting the error.
The template:
<% if defined?(source[:blacklist]) %>
"blacklist": [
<% source[:blacklist].each do |listed| %>
"<%= listed %>"
<% end %>
],
<% end %>
output of source[:blacklist] when no loop:
"[\"/var/log/httpd/access.log*\", \"/var/log/httpd/error.log*\", \"/var/log/httpd/ssl_request_log\", \"/var/log/httpd/access_log\", \"/var/log/httpd/error_log\"]"
error:
undefined method `each' for nil:NilClass
Your array is not present, if it was it would actually be a string.
Using defined?(source[:blacklist]) presents an issue as it will return true if it's not an array, e.g. defined? nil is "nil" which is truthy.
Step 1: convert to array
If you cannot change how the data is being generated, parse it into a Ruby array, defaulting to an empty array if there is an unexpected data or none at all.
blacklist = source[:blacklist].gsub(/(\[\"|\"\])/, '').split('", "') || []
Step 2: loop if the array exists and with content
<% if not blacklist.empty? %>
If source[:blacklist] is nil then defined? source[:blacklist] will return the string "method" and that's "truthy".
So it will fall through and you'll get the error you see... Undefined method each for nil:NilClass
When you say "output of source with no loop"... is that in the controller or did you check the output in the erb file? It could be the value's not being passed to the erb, and you typically want to use instance variables to pass data to html.erb files.
Also, you should note that the output you show for source[:blacklist] is actually a string, not an array, so even if it was passed you would still get an error on the each method.
is it possible to add html-content inside a link_to helper in HAML?
i tried this, but all i get is a syntax error:
= link_to "Other page", "path/to/page.html"
%span.icon Arrow
expected output:
Other Page<span class="icon">Arrow</span>
You should use block
= link_to "path/to/page.html" do
Other page
%span.icon Arrow
If anyone is still using Rails 2.x on a project, it looks like the accepted answer returns the block, thus duplicating the link in the markup. Very simple change: use - instead of =
- link_to "path/to/page.html" do
Other page
%span.icon Arrow
The simplest way to do it is by using html_safe or raw functions
= link_to 'Other Page<span class="icon"></span>'.html_safe, "path/to/page.html"
or using raw function (recommended)
= link_to raw('Other Page<span class="icon"></span>'), "path/to/page.html"
Simple as it can get !!
Don’t use html_safe method unless you’re sure your string isn’t nil. Instead use the raw() method, which wont raise an exception on nil.
I've got a Model Task with a member due_date. I'm using Chronic to take natural language input from the user and convert it to a Time, which then gets saved to the model.
I'm just not sure the best Rails, MVC-ish way to handle these use cases:
Display a formatted string (with some logic involved) to the user every time I show Task.due_date
Allow the user to input plaintext and have it parsed automagically everywhere they can edit Task.due_date
A helper method to format time was my first idea, like this:
<%= format_time task.due_date %>
combined with an overloaded setter on an accessor in my Task model, like this:
attr_accessor :due_date_string
def due_date_string=(string)
self.due_date = Chronic.parse(string)
end
This works everywhere I want it to except in my forms for editing:
<div class="field">
<%= f.label :due_date %>
<%= f.text_field :due_date_string %>
</div>
I don't know how to make the f.text_field element 'wire up' properly so that it saves to :due_date_string, but uses the helper method to display the string.
I don't necessarily need specific code examples, just looking for the kind of pattern that pro Rails-ers would use here.
Thanks!
With according to MVC conventions, data handle is about Model layer responsibility.
So you are going in right direction to do a setter (wrapper for due_date attribute):
You need to check that is attr_acessible that is access to get a data from params
def due_date_string=(string)
self.due_date = Chronic.parse(string) || Date.today
end
The representation logic to show the parsed date is Helper layer responsibility
In order to use:
f.text_field :due_date_string
Don't you also need a getter for the new attribute? e.g.,
def due_date_string
format_time self.due_date
end
Perhaps share what error or failure occurs when you use the custom text field. :)
Useful additional info: I am using the decent_exposure gem so this might be the issue - correcting the code below:
expose(:get_filter_tags) do
if params[:filter_tag_names]
filter_tag_names = Array(params[:filter_tag_names].split(" "))
filter_tags = Array.new
filter_tag_names.each do |f|
t = Tag.find_by_name(f)
filter_tags << t
end
end
end
So, something funny happens when I call this in the view:
query string ?utf8=✓&filter_tag_names=test
<% get_filter_tags.each do |ft| %>
<%= ft.name %>
<% end %>
Error message: undefined method `name' for "test":String
Why is this trying to call name on a string not a Tag object? If I put the following in the view, and have jut one filter_tag_names item
def getfiltertag
Tag.find_by_name(params[:filter_tag_names])
end
#view
<%= getfiltertag.name %>
query string: ?utf8=✓&filter=test
like above then I can call name just fine, so obviously I am doing something wrong to get an array of strings instead of objects. I just don't know what. Any suggestions?
Your problem is that each returns self — so if you write filter_tag_names.each, it returns filter_tag_names. You could fix this by explicitly returning filter_tags, but more idiomatically, you could just rewrite it as:
expose(:get_filter_tags) do
if params[:filter_tag_names]
filter_tag_names = Array(params[:filter_tag_names].split(" "))
filter_tag_names.map {|f| Tag.find_by_name(f) }
end
end
Just as an aside, this method will return nil if there aren't any filter tag names. You may want to do that, or you might want to return an empty collection to avoid exceptions in the calling code.