I am building a prototype of a education application using Rails 3, omniauth and the facebook graph api. So when a User log in to my application he uses his facebook account, I grab all his education history and his friends education_history.
I would like to group every User friends education likes this:
I have tried something like this:
<ul class="friends-list">
<%= current_user.friends.group_by(&:highschool_name) do |highschool_name|
p "<li>#{highschool_name}</li>"
end
%>
</ul>
And I get a syntax error.
The User tabel look like this:
[id, name, image, location, highschool_name, highschool_year, college_name, college_year, graduteschool_name, graduate_year ]
And the Friend tabel looks like this:
[id, uid, name, image, higschool_name, college_name, graduateschool_name, user_id]
How do solve my problem using active record, without loops because their are not effectivity.. right?
You can't use p or puts in ERB files. Think of ERB files as one big string concatenated together. Like "string 1" + "string 2" + "string 3".
That's all ERB does - it just pastes strings together into one big string. You can't call puts inside this concatenation operation. So everything in the ERB file needs to be a string. The output from a puts call just 'goes up in smoke' since a puts call does not return a string, it writes to stdout instead.
Next we look at group_by: it returns a Hash:
---------------------------------------------------- Enumerable#group_by
enum.group_by {| obj | block } => a_hash
------------------------------------------------------------------------
Returns a hash, which keys are evaluated result from the block,
and values are arrays of elements in enum corresponding to the key.
(1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
So putting everything together we could do something like this:
<% current_user.friends.group_by(&:highschool_name).each do |hsname, friends| %>
<% next if hsname.blank? %>
<li><%= hsname %></li>
<% friends.each do |friend| %>
<%= image_tag(friend.img_url) %> # <- Or wherever you get the img url from
<% end %>
<% end %>
Related
I am trying to compare the names of the element at the current index and the previous index for each element to determine if they are the same name so I don't print out the name twice.
Unfortunately, trying to access the array element using array[i] doesn't work, but if I hard-code an index or just print out the index, it works fine so I'm not sure where it's messing up.
I need to be able to access the previous element though so I can't use other loops so only suggest something where I can access the previous element in the array.
<% for i in 1..count %>
<% if array[i].count > 1 %>
<% if array[i-1].name == array[i].name %>
<%= array[i].name %>
<%= array[7].name %>
<%= i %>
<% end %>
<% end %>
Does anyone know the correct way to access an element in an array?
This should do it if your list is sorted and all you care about is printing names:
<% array.map(&:name).uniq.each do |name| %>
<%= name %>
<% end %>
More generally, you can do it like this:
array.each_with_index do |el, i|
prev_el = array[i-1] #will be nil for the first element
next_el = array[i+1] #will be nil for the last element
if prev_el && el.name == prev_el.name
#name same as previous
end
if next_el && el.name == next_el.name
#name same as next
end
end
You should avoid index-based array access for loops, not because they don't work but because there are much nicer and more readable ways of looping through arrays in Ruby.
You can keep in mind that you are using Ruby, and the motto of Ruby is "Do More in Less Work".
You can use uniq to filter out all similar elements, then iterate through them to do whatever you want to do. uniq works like this:
a = [ "a", "a", "b", "b", "c" ]
a.uniq # => ["a", "b", "c"]
This should do it all what you tried to do:
<% array.uniq.each do |obj| %>
<%= obj.name %>
<% end %>
Just thought of another way of doing this:
grouped = array.group_by(&:name)
Now you have a hash where each key is a unique name and the corresponding value is all the array elements with that name. So next you can do stuff like
#list of names in alphabetical order
grouped.keys.sort
#get one element for each unique name
grouped.map{|name,els| els.first}
#print out how many you have for each name
grouped.each{|name, els| puts "#{name.inspect} => #{els.size} elements"};false
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 have this code in controller:
array = ["asd", "asd", "asd"]
#print = array.each do |i|
puts "Random text #{i}"
end
And now I want to print it in some pages view like show.html.erb:
<%= #print >
And I get this: ["asd", "asd", "asd"] But In controller I sayd to puts each object in array, but it is not doing it?
The puts method is for printing a string to the console. If you wanted to set each of the values of the array to a certain value in order to print it out later, you should use #map.
array = ['asd', 'asd', 'asd']
#print = array.map { |i| "Random text #{i}" }
Now, in your corresponding view, you should add:
<% #print.each do |val| %>
<%= val %>
<% end %>
puts prints to the stdout (standard output) that, in the majority of cases, corresponds to the console where you started the Rails server.
Check the console and you will find, in the middle of the request logs, also the result of the puts statement.
A better way to print out something from the console is to use the Rails logger, especially if you want such output to be logged in the logs in production.
Rails.logger.info "message"
Assuming it's just for debugging purpose, then it's fine to use puts (or p).
You should be doing the looping in your view. This helps maintain the separation between your application logic and your view code.
Controller
#array = ["asd", "asd", "asd"]
View
<% #array.each do |i|
<%= i %> # No need to use the puts method here
<% end %>
it seems that the variable #print is the array. The controller is run once per load of the page and then will output its contents at the end to the view. Plus, "puts" is for printing a string to the console. You should put the loop in question in the view like this:
<% #array.each do |i| %>
<%= i #>
<% end %>
When I'm in irb and I do something like this:
node_list.each_element { |e| puts e.text }
It works and prints one line of text per element returned (plus I think it returns the xml object). However, when I head over to rails and have things moving between controllers, helpers, views and layouts it just dumps the xml object.
I should mention that for good reasons I'm using rails 1.2.3 and ruby 1.8.7.
Gratzi!
So the issue your having is that puts writes to console and not the template. Also, in ruby the a method will return by default its last object. So your method as written will loop through #child1, print each's text to the console, and then return the #child1 object at which point your erb tags of <%= %> tells it print the object (#child1 in this case)
You have two options, either you can move it out into the template:
<% tol_get_names(#child1) do |e| %> #note just <% and not <%=
<%= e.text %>
<% end %>
Or build your method so that it loops through building a string and then returns that string instead of the original object:
def tol_get_names(child)
texts = [] #empty array for all our values
child.each_element { |e|
texts << e.text #add the text string to our array
end
texts.join(", ") #build a string and seperate it with a comma
end
Several ways you could write this type of method, but this is my usual way.
I'm using Rails 3.0 and the acts_as_taggable_on gem. I have a Candy model and candies can have multiple tags for flavors. Let's say
Candy1.tags #['apple', 'orange']
Candy2.tags #['orange', 'banana']
Candy3.tags #['apple', 'kiwi']
I want a list of tags with associated candies below them, like so:
Apple
Candy1
Candy3
Orange
Candy1
Candy2
...etc.
I've tried
Candy.all.group_by{ |candy| candy.tags }
but that treats the array of tags as a single entity, returning something like this:
['apple', 'orange']
Candy1
['orange', 'banana']
Candy2
Lacking a group_by_each method, whats the best way to accomplish this? Another Stack Overflow question explains how to do this in memory with simple hashes, but I wonder if there's a more database-oriented way to do it with ActiveRecord associations.
You can iterate over the candies and store them on a hash base on the tag:
grouped = {}
Candy.all.each do |candy|
candy.tags.each do |tag|
grouped[tag] ||= []
grouped[tag] << candy
end
end
At the end you will get:
{'apple' => [candy1, candy2], 'orange' => [] ...}
Hope this helps you
candies = Candy.all.inject({}) do |memo, candy|
candy.tags.each do |tag|
memo[tag] ||= []
memo[tag] << candy
memo
end
end
Now candies is a hash like this:
{
'apple' => [Candy1, Candy3],
'orange' => [Candy1, Candy2],
...
}
Which you can iterate over nicely:
candies.each do |key, value|
puts "Candy tag: #{key}"
value.each do |candy|
puts " * #{candy}"
end
end
In rails api documentation that group_by is for collecting enumerable. I think you need to try a more classic array iterator like the following since you've strings data
in views/candy/index.html.erb
<% #candys.each do |candy| %>
<%= candy.name %>
<% end %>
<%for tag in candy.tags %>
<li> <%= tag.name(or flavor %> </li> #tag.name_attribute
<% end %>
<% end %>
Let me know if it works