Rails Getting Started Question - ruby-on-rails

I'm a newbie in rails, and I've been looking all over for an answer for this issue. Here's what I have:
class Item < ActiveRecord::Base
belongs_to :book
class Book < ActiveRecord::Base
has_many :items
Now I want to list all the items with their properties and the book associated with them. They would go under index in the items_controller.rb
class ItemsController < ApplicationController
# GET /items
# GET /items.xml
def index
#items = Item.all
now how would I handle books in the ItemsController so I can list them in index.html.erb keeping in mind that an item belongs to only one book? if I add:
#books = items.book.find
right under #items = Item.all so I can reference them in the index.html.erb I get:
undefined method 'book' for #<Array:0x10427f998>
I have a feeling that the answer is so simple but so far I haven't figured it out. Is there any tutorial that you guys are aware of that covers this matter?
Thank you!

In your view, when you iterate over all of your #items, just reference the book for each one. Example ERB (app/views/items/index.html.erb):
<% #items.each do |item| -%>
Item: <%= item.name %>
Book: <%= item.book.title %>
<% end -%>
If instead your intention is to display each book with the associated items under each book, you'd be better off using the index action on the BooksController. Find all the books, iterate over each book, and for each book, iterate over the items for that book.

The array of items doesn't have a book, each individual item does. It looks like you're trying to get the book of ALL the items, which doesn't exist.
Try #items[0].book or using a loop in your view:
<ul>
<% for item in #items %>
<li><%= item.book.title %></li>
<% end %>
</ul>
You could also use a partial to iterate through the array. See the section "Rendering a collection of partials" at http://api.rubyonrails.org/classes/ActionView/Partials.html

The problem is that you're calling items.book on an array of items, and the array doesn't have a method named book (hence the error). You'd need to get a single book from that array (such as items[0]), then call .book on that.

Related

How to filter collections in rails

I'm new in Rails, and I'm trying to filter the animals I have on my DB, by one of their properties. I have read that I can make it by a scope in the controller, and have access to it by a parameter on the URL, but I think that doesn't work for me because I'm using a loop to create my HTML.
Is there a way to add a filter to the collection I'm using (#animals)?
<% #animals.each do |animal| %>
<li>
<a href="#">
<%=link_to animal.ncommon, animal %>
</a>
</li>
<% end %>
I hope I was clear with my question. Thank you for your help!
So the best practice is to move the scope to the models , not in the controller. Here is and example. (please note that this may change depending on your file structure and names).
here I'm going to filter animals by type. Lets say type 1 and type 2.
#model app/models/animal.rb
class Animal < ActiveRecord::Base
scope :by_type, -> (ty) { where(type: ty) }
end
#controller app/controllers/animals_controller.rb
class AnimalsController < ApplicationController
... other code
def index
# calls the by_type method/scope in the Animal model
# filter the records and assignes them to #animals varaible
#animals = Animal.by_type(params[:type])
end
... other code
end
then you can use your loop in the view. When you want to filter, you call the index action with a parameter
E.g http://localhost:3000/animals?type=1
So the idea is, not to filter inside the loop, but to get the filtered results to the #animals variable.
I just found a solution that i can use in the loop.
I changed:
<% #animals.each do |animal| %>
to:
<% #animals.where("promo > ?", 0).each do |animal| %>
Here i´m getting all the animals that has a promo greater than zero.
Thanks!

Display multiple model results in your views in rails app

I'm adding a new model to my equasion and I'm wondering if there is a way to associate two models into one model then display any/all results within a view. For example, here is what I've currently have;
#tweet_category.order("position").each do |tweet|
<%= tweet.title %>
end
just a short example... now what if I added facebook into this. I was first thinking of creating a model thats named stuff then associate it to tweet_category and facebook_category like so;
class Stuff < ActiveRecord::Base
attr_accessible :title
belongs_to :user
has_many :tweet_category
has_many :facebook_category
end
Now in my controller I'm guessing I would do the following;
class StuffController < ApplicationController
def index
#stuff_list = Stuff.find(:all)
end
end
and in my view I would just simply do the following from above view;
#stuff_list.order("position").each do |stuff|
<%= stuff.title %>
end
am I understanding the logic here??? would that work having two models / two tables db.. etc..
First of all, I don't understand why you would need that "stuff" model. It belongs to users and has_many tweet_category and facebook_category, and just does nothing but offering a "title", when your User model could do the job ( I mean, each user could have many tweets and fb category, instead of having one or several "stuff" which has/have many of them ).
Anyway, if you want to make links between your models and then display everything in a view, first in your User model you just have to do :
class User < ActiveRecord::Base
...
has_many :facebook_categories #( I don't know how rails would pluralize it, btw, I'm just making an assumption )
has_many :tweeter_categories
end
and
class Facebook_category
...
belongs_to :user
end
and do the same fot the tweeter category
Then in your controller :
def show_everything #Here it's a custom action, but you can call it wherever you want
#users = User.all
end
And finally in your view :
<% #users.each do |user| %>
<% user.facebook_categories.all.each do |fb_c| %>
<%= fb_c.title %>
<% end %>
<% user.tweeter_categories.all.each do |t_c| %>
<%= t_c.title %>
<% end %>
<% end %>
Maybe just try to grab a better name for your models, so the pluralization doesn't get messy ( and I saw that the ".all" method is deprecated, so maybe replace it with something
Hope it helps !
Edit :
Basically, when you're doing
#users = User.all
What rails' doing is putting every hash defining every "User" in an array. So, if you want to mix two tables' arrays inside a single array, you can do something like this :
#categories = [] << Facebook_category.all, Tweeter_category.all
You will then have an array ( #category ), filled with 2 arrays ( one ActiveRecord relation for Facebook_category and one for Tweeter_category ). Themselves filled with hashes of their model. So, what you need to do is :
#categories.flatten!
Here's the API for what flatten does ( basically removing all your nested arrays inside your first tarray )
Now, you got a single array of hashes, being the informations from both your model's instances. And, if these informations can be ordered, in your view, you just have to :
<% #categories.order("updated_at").each do |i| %>
<%= i.title %>
<% end %>

how to show count of each category list rails

I have the following view to show the categories with the count
<% #categories.each do |category| %>
<% category.sub_categories.sort.each do |sub_category| %>
<li><%= link_to sub_category.name, "category/#{sub_category.slug}", title: sub_category.name.capitalize %> <%= sub_category.posts.where(status: 1).count %></li>
<% end %>
<% end %>
But I dont think using where in view is not good idea. Is there any other way to perform such operation.
I am getting correct count but I need better way to do this. can anyone help
Your Post model should have a scope on it that encapsulates this status logic:
class Post < ActiveRecord::Base
def self.active
where(status: 1)
end
end
Then call it like so from the view:
sub_category.posts.active.count
use scope to do the same thing, your solution is ok otherwise. you don't need to do this controller.
scope :active_posts, lambda{ where(status: 1)}
The only problem I see with this is it causes N+1 queries, because you do 1 query for the categories THEN another query for EACH category. This is ok with small quantities, however can cause serious performance problems later on.
1) I recommend you look into "counter_cache"ing:
- http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-belongs_to
2) OR upon activation/deactivation of Posts, create a method that will increment/decrement a attribute on the Post's Category (i.e. "active_posts")

how to generate link to next product in same category, rails

I want to achieve such function.
I am currently viewing exact product, like, John Deer tractor, who is under category Tractors.
How can I generate link so that clicking on it it will send me to next tractor under Tractors category?
I am familar with some pagination like Kaminari and Will paginate, but can I do such thing without pagination gems ?
At this moment I don't have any idea to show, or what I have tried.
Thanks
Sure you can, let's say you have this model
class Category < ActiveRecord::Base
has_many :products
def previous_product(product)
products.where("created_at < ?", product.created_at).last
end
def next_product(product)
products.where("created_at > ?", product.created_at).first
end
end
You could also move the scoping logic to the Product class too :)
-- EDIT --
Inside the view, something like
<% next_product = #category.next_product(#product) %>
<% if next_product %>
<%= link_to next_product.title, product_url(next_product) %>
<% end %>

How to iterate over multiple model results in Rails 3?

I am not sure what I am doing wrong here. I find many examples that show that I am doing this right and it is really basic stuff, I know.
I am simplyfying a bit, but I have two models, 'Post' and 'Category'. I am trying to get the list of categories from the database and list them by name.
class Post < ActiveRecord::Base
has_and_belongs_to_many :categories
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :posts
end
# get all categories and output the names
cats = Category.all
cats.each do |cat|
cat.name
end
It instead seems to output the entire array of retrieved results. All results not even just the one I am iterating over. What gives?
Where are you putting that .each loop code? Where is the "output" code you're referring to? If you're using a loop in a view, make sure you're using
<% %>
and not
<%= %>
for the loop lines themselves. As in:
<% Category.all.each do |cat| %>
<%= cat.name %>
<% end %>
Category.all returns an array of all Category objects, which is everything the categories table contains. cats is therefore an array of all the categories. I'm not sure why you think you're only iterating over "one" of anything. To get one result, you can use find() or first:
cat = Category.first
puts cat.name
If you want all the names, you can do this:
Category.all.map(&:name)
or, a bit more efficiently, especially if there are many fields:
Category.all(:select => :name).map(&:name)

Resources