I am trying to create helper method that displays the navigation. How ever my helper displays an array even though i am using content_tag. Was wondering if i was doing something wrong.
module SubscriberNavigation
def navigation
get_menu_items.find_each.map do |menu|
content_tag(:li, link_to("#{ menu.title.try(:capitalize) }", "#{ menu.url.downcase }"))
end
end
def get_menu_items
#get_menu_items ||= Subscriber::Menu.all
end
end
And when i display
<%= navigation %>
An array of records in being displayed. Instead of content_tag list items.
["<li>Contacts</li>", "<li>Terms and conditions</li>", "<li>About us</li>"]
I tried .html_safe etc but looks like i'm missing something.
It is returning an Array. You can try this:
<%= navigation.join(' ').html_safe %>
Related
I'm building a Rails app where I have individual entries called films. I would like to display the latest entry's link on the homepage (separate controller) and I'm struggling to make it work.
My films_controller.rb is as follows (excerpt):
def show
#film = Film.find(params[:id])
end
My home_controller.rb only has the following:
def index
end
And my view file (index.html.erb) has the following:
<%= link_to #film.last.filmTitle, film_path(#film) %>
I'm getting the following error:
Couldn't find Film with 'id'=#<Film::ActiveRecord_Relation:0x007fc93f2d1fd0>
With the #film.find(params[:id]) highlighted.
Thanks!
The last method:
Find the last record (or last N records if a parameter is supplied). If no order is defined it will order by primary key.
source
You can add a #last_film instance variable in your index controller and use it in the view.
def index
#films = Film.all
#last_film = Film.last
end
and in your index.html.erb
<%= link_to #last_film.filmTitle, film_path(#last_film) %>
The index method need something, currently, it didn't connect with ActiveRecord like model or table, that's why
Couldn't find Film with 'id'=#<Film::ActiveRecord_Relation:0x007fc93f2d1fd0>
So if you need to show recent posts in the index then you could something like this
def index
#films = Film.limit(10).order(created_at: :desc) #=> or you can use id
end
it will show last 10 records, for this in the index.html.erb like this
<% #films.each do |film| %>
<%= link_to film.filmTitle, film_path(film) %>
<% end %>
In the other hand if you need to show only one post which is the last then you should modify this query like this like limit(10) to limit(1) or you can use use the last method like this
def index
#film = Film.last
#or
##films = Film.limit(1).order(created_at: :desc) #=> or you can use id
end
if you use this #film = Film.last then your index file will like this
<%= link_to #film.filmTitle, film_path(#film) %>
otherwise, you need to use each method which describes before.
In my user profile view I have this:
#show.html.haml
%p
%b Categories
= list_self_reviews(current_user.self_reviews)
The list_self_reviews helper looks like this:
#profiles_helper.rb
def list_self_reviews(reviews)
self_reviews = {}
reviews.each { |review| self_reviews["#{review.get_category_name}"] = "#{review.body}" }
self_reviews.each do |key, value|
puts "#{key} (#{value})"
end
end
I'm creating a hash of review category names and the body of the review and trying to print them in the profile view in the format "[Category Name]: [Review Body]." However, in the view the entire hash is being printed out, so that it looks like this:
{"organizing"=>"I'm a pretty organized guy", "tutoring"=>"helped with spanish"}
It should just say "organizing: I'm a pretty organized guy" and then the other one below it. What am I missing here about how to return this correctly in the view?
Change your profile view file(show.html.haml) as follows
%p
%b Categories
- current_user.self_reviews.each do |review|
= "[#{review.get_category_name}]: [#{review.body}]."
%br/
It's what gets returned from the method that's important - that's what gets inserted into your HTML. puts is for outputting to the console only. Your method is implicitly returning the self_reviews hash because it is the last thing evaluated (with self_reviews.each). As it currently stands, you need to build a single string with all your list items (would likely need to contain HTML) and return that instead.
That being said, I feel like your code could be made neater with something like:
#show.html.haml
%p
%ul Categories
- current_user.self_reviews.each do |review|
%li = review_item(review)
#profiles_helper.rb
def review_item(review)
"#{review.get_category_name}: #{review.body}"
end
...or even no helper at all (like the other answer).
Edit - or you could do something like this:
#show.html.haml
%p
= review_list
#profiles_helper.rb
def review_list
content_tag :ul, "Categories" do
current_user.self_reviews.each do |review|
content_tag :li, "#{review.get_category_name}: #{review.body}"
end
end
end
but personally I prefer my template to be a bit more explicit, and you might be better off using a partial in this case.
I am trying to create a search function in Rails 4. I have it implemented properly and it is displaying the result I want, however it is also returning and displaying the entire database query - All columns from table including password digest etc. I have done this before but haven't run into an issue like this. Would like to know if I am doing something wrong.
here is my controller:
def index
if params[:search]
#pro = Admin.search(params[:search])
else
#pro = Admin.all
end
end
Admin Model:
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
And here is my views:
<%= #pro.each do |ind| %>
<ul>
<li><%= ind.name %></li>
</ul>
<% end %>
in Chrome, I see the returned name of the individual from the search, as I would like, plus meta data such as id: 1, admin_id: 2, name "", email: "", password_digest: "" etc. in an array format. This is what's stumping me, not sure why it's displaying this.
When I inspect the page in chrome, the array is just pasted right under the tags.
It goes away when I remove the entire .each method on #pro. Any insight anyone can provide is appreciated.
The line in view should be <% #pro.each do |ind| %>. If you're doing <%= %> the result is the actual #pro array, which is why you're getting it pasted under the tags.
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?
I have the tag functionality working ok but can't generate a tag_cloud
in my controller:
def tag_cloud
#tags = Article.tag_counts # returns all the tags used
end
in the view:
<% tag_cloud Article.tag_counts.sort { |x, y| x.name <=> y.name }, %w(x-small small normal large x-large) do |tag, css_class| %>
<%= link_to tag.name, tag_url( :tag => tag.name ), :class => css_class %>
<% end %>
I always get a undefined method error for tag_cloud
You can't call controller methods from the view. Try putting it in a model or passing it to the view from the controller.
If this isn't helpful enough, try editing the question and including more details such as the full definition of tag_cloud, explain why you're setting #tag but not using it, etc.
That code doesn't look like it'll do all you want, but to remedy the undefined method error, the proper place for auxiliary methods for views is in the helper, so move the method tag_cloud there instead.
You'll find it in app/helpers/controllername_helper.rb.
tag_cloud defined in module TagsHelper. You need to include it in corresponding helper:
module ApplicationHelper
include TagsHelper
end
Also there is no need in controllers tag_cloud
sergeykish.com is correct, you just need to include the helper in /app/helpers/application_helper.rb
module ApplicationHelper
include TagsHelper
end