What's happening when Ruby shows something like this: #<Role:0x11157b630>? - ruby-on-rails

I remember coming across this when first watching some Ruby videos, but I can't find it again. When Ruby shows something like this:
#<Role:0x11157b630>
,what is going on?
I have three roles (admin/staff/client) and I would like to show one of these, not
#<Role:0x11157b630>.
Any idea how I could do that?
Cheers!

What you're seeing is just a representation of the instance you've got. Say you have a title attribute on the class Role, you could, instead of logger.debug #role do something like logger.debug #role.title. If you want just doing logger.debug #role to print out something more useful, define a to_s method on Role.

Appending an inspect method should show some more details.
#role.inspect

That's what the default implementation of to_s looks like; class name followed by memory location. You can define your own version if you like:
def to_s
"My name is #{#name}"
end

When I started with rails I had strange bugs sometimes when I made something simple like:
<% #posts.each do |post| %>
....
<% end %>
I would get those strange outputs under the list of posts.
For example:
#<Post:0x11157b630>#<Post:0x11157b630>#<Post:0x11157b630>
Turns out I accidentally put a "=" in there before the loop.
<%= #posts.each do |post| %>
....
<% end %>

According to The Secret of Object#to_s, the number in #<Role:0x11157b630> is double the object's object_id in hexidecimal.

Related

View helper method that lists images in a directory with `Dir.glob` and `each ... do` not working

My goal is to be able to include a helper method in my Rails 4 project that will list all images in a particular directory in a view so that I don't have to manually add image_tags each time I add a new image.
I've come across several examples of this, but for my purposes I'd like to allocate this job to a helper method, and I can't for the life of me understand why this isn't working.
myapp_helper.rb
module MyAppHelper
def list_logos(clss)
logos = Dir.glob("engines/myapp/app/assets/images/myapp/logos/*.{gif,png,jpg}")
logos.each do |logo|
content_tag("li", class: clss) do
image_tag logo.gsub("engines/myapp/app/assets/images/", "")
end
end
end
end
show.html.erb
<%= list_logos("companies__company") %>
This just prints out the Dir.glob array. Before, I had tried image_tag("myapp/logos/#{image.split('/').last}" to no avail, and so I thought I might have better luck with the gsub method. Nope.
Funny thing is, if, in my helper method, I just write:
logos = Dir.glob("engines/myapp/app/assets/images/myapp/logos/*.{gif,png,jpg}")
image_tag logos.sample.gsub("engines/petitions/app/assets/images/", "")
the image renders fine, which leads me to believe that it's the logos.each iteration which is failing.
I'm stumped. I'll add that this is an engines-based project that I've inherited, and I'm a relative newbie when it comes to Ruby and Rails, so I very well could be missing something simple. Yay! Thanks in advance.
You need to concatenate and return the tags. Try something like this:
module MyAppHelper
def list_logos(clss)
logos = Dir.glob("engines/myapp/app/assets/images/myapp/logos/*.{gif,png,jpg}")
logos.map do |logo|
content_tag("li", class: clss) do
image_tag logo.gsub("engines/myapp/app/assets/images/", "")
end
end.join
end
end
Also, since you're constructing HTML in the helper, you'll need to use html_safe in the template:
<%= list_logos("companies__company").html_safe %>
Oh, and the reason you saw the result of Dir.glob is that each returns the object it's called on.
module MyAppHelper
def list_logos(clss)
logos = Dir.glob("engines/myapp/app/assets/images/myapp/logos/*.{gif,png,jpg}")
list_items = logos.map do |logo|
content_tag("li", class: clss) do
image_tag logo.gsub("engines/myapp/app/assets/images/", "")
end
end
list_items.join
end
end

Getting text to show up if a condition is true

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?

Rails Check if User Id is in Array

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.

Basic question on Ruby Rails

Suppose I have model xyz.rb and model abc.rb. No relation between them. If want to print any attribute from xyz in abc views/print/show.html.erb how??
I know very basic but looking for good explanation.
You can access any model from any controller, view or helper method. Mvc means model, controllers and views are related but there's no limitation on access between them. The normal thing to do would be to store the reports to an instance variable in any controller then output them in the view:
#print_controller.rb
def show
#reports = Report.find_by_some_attribute(...
#show.html.erb
<%- #reports.each do |report| -%>
<%= report.created_at -%>
<%- end -%>
I really think though that you need to find a better approach to learning rails. This is very basic like you say and I would recommend you buy a book. Do you speak English well, or what's your native language?
Something like:
XYZ.all.each do |xyz|
some(xyz)
end
Details you can find here.
Sure you can.
Assuming #x is an instance of Xyz model, you can do print any attribute of #x object.
If you dont have #x object. You can find it and instantiate #x in the show action of the abc controller. #x = Xyz.first for example.
Considering your example, if you have two models User and Report. You can access Report's created_at from User's controller,view,etc.
You need to write something like this:
Report.find_by_created_at("2013-11-12 14:43:44.11824")
You can refer ruby on rails guides to learn rails. Also you can find basic active record explanations here
This very basic but i am giving best solution to this
in abc controller
def show
#reports = Report.where(:attribute => value)
end
it will get the all records basic on that value
<h1>views/abc/show.html.erb</h1>
<% #reports.each do |report| %>
<%= report.attribute_name %>
<%end%>

Dealing with nil in views (ie nil author in #post.author.name)

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!)

Resources