I'm trying to get the text "Tags:" to show up only if tags are present, so I did the following in my view:
<% if #tags.present? %>
<%= puts "Tags:"%>
<% end %>
Which doesn't work... I'm a beginner, and have no idea what I'm doing wrong.
Thanks
EDIT:
A tag belongs to an Article.
Tags is defined in my Article model as:
def tag_tokens
self.tags.collect{|t| t.name}.join(", ")
end
def tag_tokens=(tags_delimited)
tags_delimited.split(",").each do |string|
self.article_tags.build(:tag => Tag.find_or_create_by_name(string.strip.downcase))
end
end
I'm trying to make it so that when an article has tags the word "Tags:" shows up before the list of tags, and when an article doesn't have any tags, the word "Tags:" doesn't show up.
Right now <% if #tags.nil %> just causes "Tags:" to show up on every post.
You don't use puts in views -- puts causes the text to go to your console. This will fix it:
<% if #tags.present? %>
<%= "Tags:"%>
<% end %>
You also don't need to use .present? by the sound of it. If you only want to see if it's been set, you should use .nil? instead. You can also condense this down to a single line.
<%= "Tags:" unless #tags.nil? %>
UPDATE: It looks like the tag_tokens method is broken for you in both the getter and setter. Your setter isn't actually saving anything by the looks of it (.build returns a new object, you need to save it). Your getter is also referencing tags, instead of article_tags which is what you're trying to save by the looks of it. Changing it to this should work for saving:
self.article_tags.build(:tag => Tag.find_or_create_by_name(string.strip.downcase)).save
This is assuming that you have a line that is something like:
has_many :article_tags
has_many :tags, through: :article_tags
Which I'm assuming you do based on your setter.
I assume this is a many-to-many relationship, but it looks like you're using has_many :through, rather than has_and_belongs_to_many. Is there a reason for this? If you're using has_and_belongs_to_many you should be able to do this:
has_and_belongs_to_many :tags
def tag_tokens=(tags_delimited)
self.tags = []
tags_delimited.split(",").each do |string|
self.tags << Tag.find_or_create_by_name(name: string)
end
end
If you do that, you should not have an ArticleTags model at all, and you should have a table called articles_tags with no primary column, and an article_id and tag_id column.
Update 2:
You're not setting #tags to anything, which is why it's always nil. #tags is a variable, which needs to be set to have a value just like #articles is being set in your controller's index method. Regardless, since this is for an index method, you wouldn't want it to be a single instance variable regardless. You should be accessing your tag_tokens method for that particular instance. app/views/articles/index.html.erb lines 53-55 should be changed to this:
<%= "Tags:" if article.tags.any? %>
Check the answer by sgrif, it contains a lot of good points. To just answer your main question:
In erb (the "language" used for view templates in Rails) you can use <%= ... %> to interpolate the result of some Ruby code into your view template.
When you are doing:
<%= puts "Tags:" %>
the following happens:
Ruby evaluates/executes your code: "Tags: " is printed to STDOUT and nil is returned since a call to puts alsways returns nil
erb interpolates the result into your template, the result is nil, which shows up as "nothing"
To fix it, just use:
<% if #tags.present? %>
<%= "Tags:"%>
<% end %>
or, since you are not doing anything in Ruby, you can just use:
<% if #tags.present? %>
Tags:
<% end %>
What has #tags been defined as? Where do you want to check if it is present?
Do you want if #tags.nil?
Related
new ruby on rails user here. I have a question about the following few lines of code.
First example in view.
<% sailing.travelling_parties.each do |party| %>
<% party.party_registers.each do |reg| %>
<%= reg.user.detailed_user.first_name %>
<% end %>
<% end %>
When I run it in the in view, i get my expected result which is multiple names printed out. When I move it to the model and change it to the following,
Second example, in model. The ** represents what I'm actually trying to accomplish in this entire example.
class Sailing < ActiveRecord::Base
...
def gather_data
self.travelling_parties.each do |party|
party.party_registers.each do |reg|
reg.user.detailed_user.first_name
** use a variable to count loop iterations **
end
end
end
Second example, in View
<%= sailing.gather_data %>
This is printing out an array filled with the 'travelling_parties' I am trying to iterate over, not what I had expected at all! So, obviously it only loops once regardless of how many names are in the sailing record.
Can any shed any light on why this is happening, and how I can get it to work like the first example, without actually putting my business logic in the view?
Thanks
You can use Array#map, which transforms array into other array according to given block:
def gather_data
travelling_parties.map do |party|
party.party_registers.map do |reg|
reg.user.detailed_user.first_name
end
end
end
This method returns array of arrays with first names. If you want get one-dimensional array, use flat_map instead of first map, like below:
def gather_data
travelling_parties.flat_map do |party|
party.party_registers.map do |reg|
reg.user.detailed_user.first_name
end
end
end
I have a model that has a main_image per asset and in the attachment model this can only have one true value per asset. I am wondering if there is a way to pull this record without looping through every record to see if main_image is set to true or false.
Clarification:
I can find the value by using the following code:
<% #asset.attachments.each_with_index do |attachment, i| %>
<%= image_tag(attachment.attachment.s_640_480) if !attachment.main_image.nil? && attachment.main_image%>
<%end%>
but, I am wondering how to do this without a loop...
I don't know how to clarify any more...but something like:
<%= image_tag(#attachment.where_main_image.s_640_480) %>
I know that won't work but basically that is the concept
<%= image_tag(#asset.attachments.find_by_main_image(true).attachment.s_640_480) %>
It's not so nice to have this code in your view, so I'd recommend to put it in an instance method of your asset model:
class Asset < ActiveRecord::Base
has_many :attachments
def main_image
attachments.find_by_main_image(true).attachment.s_640_480
end
end
Then in your view you can do:
<%= image_tag(#asset.main_image) %>
You probably have to add some checks that objects are not nil. Good luck.
You can join it up like so:
class Asset < ActiveRecord::Base
has_many :attachments do
def main_image
where(:main_image => true).first
end
end
end
Use in your views like so:
<%= image_tag #asset.attachments.main_image.s640_480 %>
If i understant you need to find some entries in database if the value of it is true or false right ?
So you need to make a method inside your model or use a find with condition in the controller, you can find all what you want inside the documentation.
This question already has answers here:
What is the difference between <%, <%=, <%# and -%> in ERB in Rails?
(7 answers)
Closed 3 years ago.
I think what I'm trying to do is pretty simple, and I'm really not sure why this isn't working. I'm using Rails 3.
Essentially, I'm just trying to select the distinct values from a column in an existing model, and print them out all. For the most part, this works but the .each loop in my view also ends up printing the entire array at the end of the loop. (
I a model called Attractions, and each attraction has a Category (right now the Category is hardcoded in the DB for simplicity).
This is the Attraction Model and a class method "all_categories" defined...
class Attraction < ActiveRecord::Base
def self.all_categories
Attraction.select("DISTINCT category")
end
end
This is the Attraction Controller
class AttractionsController < ApplicationController
def index
#categories = Attraction.all_categories
#attractions = Attraction.find(:all)
end
def show
#attraction = Attraction.find(params[:id])
end
end
This is the code in my view that is causing trouble - no rocket science, just a simple iterator, ...
<%= #categories.each do |c| %>
<%= c.category %><br/>
<% end %>
Pretty simple, right? This is all running fine, BUT this is what I see when that code segment is run:
Architecture
Art
Fashion
Music
[#<Attraction category: "Architecture">, #<Attraction category: "Art">, #<Attraction category: "Fashion">, #<Attraction category: "Music">]
Why is the array at the end printed? All I want is a list of the categories:
Architecture
Art
Fashion
Music
Obviously, I'm new to Ruby/Rails, and I've tried to search all over for a solution to this. Is there something obvious that I'm missing?
Appreciate any help.
# Change this line with an =:
<%= #categories.each do |c| %>
# ...to this:
<% #categories.each do |c| %>
You only want the side effects on the block of the #each method, you don't want interpolation of the returned value.
It's because it's what happen when you do
def self.all_categories
Attraction.select("DISTINCT category")
end
It's create an Attraction Object with attribute define by your field. You can do
def self.all_categories
Attraction.select("DISTINCT category").map(&:category)
end
I want to show a post author's name; <% #post.author.name %> works unless author is nil. So I either use unless #post.author.nil? or add a author_name method that checks for nil as in <% #post.author_name %>. The latter I try to avoid.
The problem is that I may need to add/remove words depending on whether there is a value or not. For instance, "Posted on 1/2/3 by " would be the content if I simply display nil. I need to remove the " by " if author is nil.
Null object pattern is one way to avoid this. In your class:
def author
super || build_author
end
This way you will get an empty author no matter what. However, since you don't actually want to have an empty object sometimes when you do expect nil, you can use presenter of some kind.
class PostPresenter
def initialize(post)
#post = post
end
def post_author
(#post.author && #post.author.name) || 'Anonymous'
end
end
Another way is using try, as in #post.author.try(:name), if you can get used to that.
You can use try:
<%= #post.author.try(:name) %>
It will attempt to call the name method on #post.author if it is non-nil. Otherwise it will return nil, and no exception will be raised.
Answer to your second question: In principle there is nothing wrong with the following:
<% if #post.author %>
written by <%= #post.author.name %>
<% end %>
or
<%= "written by #{#post.author.name}" if #post.author %>
But if this is a recurring pattern, you might want to write a helper method for it.
# app/helpers/authors_helper.rb or app/helpers/people_helper.rb
class AuthorsHelper
def written_by(author)
"written by #{author.name}" if author
end
end
# in your views
<%= written_by(#post.author) %>
Write a method which accepts any variable and checks to see if it is nuil first, and if it is not displays it. Then you only have to write one method.
I found your question interesting as I have often come across similar situations, so I thought I'd try out making my first Rails plugin.
I'm afraid I haven't put in any tests yet but you can try it out http://github.com/reubenmallaby/acts_as_nothing (I'm using Ruby 1.9.1 so let me know if you get any problems in the comments or on Github!)
I have a calendar_date_select in a view that shows a table listing all the information on a certain phone. I want to add a To: and From: date range that a user can select and update the table in the view. The structure is like this:
Usage Controller
Detail action in the usage controller that shows the call history from a certain phone.
Inside detail I want the To and from fields with a refresh button.
What is exactly happening in this code:
<% form_for :date_range do |f| %>
<%= f.calendar_date_select :start, :time => true %>
<%= f.calendar_date_select :end, :time => true %>
<%= f.submit "Submit" %>
<% end %>
Does this pass a hash to the usage controller and look for a date_range method? My current route looks like this
usage/detail/id-of-phone
I would like it to look something like this:
usage/detail/id-of-phone#start-end
So I could then (I think) extract the start and end dates from the params with just params[:start] and params[:end]. Am I doing this right, or is there a better way to get the desired result that I want.
I haven't used the calendar_date_select plugin, but you should be getting the parameters back already.
params[:date_range][:start]
params[:date_range][:end]
What you want is the url or the smart solution to get the params?
Please set the routes.rb for the url. Or you can make many method in the 'DataRange' model.
As many programmers using, save many dates in the model. But making us terrible is using the params smartly.
Such as
class Model
def start
......
end
def end
......
end
end
You can't get the params by params[:start] if you pass the params by the form. You can see the form's html for detail.
Please use the
params[:...][:start]