I'm trying to display the number of photos a category has in a list.
For it, I'm trying to do in my view:
<%= #photos.zone.name("Zone1").count%>
<%= #photos.zone.name("Zone2").count%>
<%= #photos.zone.name("Zone3").count%>
<%= #photos.zone.name("Zone4").count%>
But this doesn't work, and I don't know if this will make a million requests to my ddbb.
Which is the correct way to do this? Making a scope for each category?
Update
class Photo < ActiveRecord::Base
# validate :validate_minimum_image_size
has_many :tags , dependent: :destroy
belongs_to :user
belongs_to :category
belongs_to :zone
validates_presence_of :title, :description, :category, :zone
acts_as_votable
is_impressionable
before_destroy { |record| record.tags.destroy_all if record.tags.any? }
class User < ActiveRecord::Base
rolify
has_many :photos
has_many :tags, through: :photos
Thanks
This line here is wrong because you are calling it on a collection, and it doesn't represent your data model correctly.
<%= #photos.zone.name("Zone1").count%>
Let's say you wanted to get the zone of each photo, you would do something like this:
<% #photos.each do |photo| %>
<%= photo.zone.count %>
<% end %>
This still does not make sense because your association states that a photo belongs to a zone. So a photo can only have one zone per your data model.
class Photo
# ...
belongs_to :zone
end
Based on this information, I will assume that you want to display zones, and the number of photos per zone. In which case you would do something like this:
<%= #zone.photos.count %>
Or, if you wanted to show multiple zones on the same page:
<% #zones.each do |zone| %>
<%= zone.photos.count %>
<% end %>
How would you prepare the data? In your controller you would do something like this:
#zone = Zone.includes(:photos).find(params[:id]) # assuming a /zones/:id path
Or for multiple zones:
#zones = Zone.all.includes(:photos) # assuming a /zones/ path
It is also possible that you want to display photos grouped by zone, which is another story.
Extending #Mohamad's answer
The best bet is to use counter_cache.In your Photo model set counter_cahe =>true for zone
class Photo < ActiveRecord::Base
# validate :validate_minimum_image_size
has_many :tags , dependent: :destroy
belongs_to :user
belongs_to :category
belongs_to :zone,:counter_cache => true #here
validates_presence_of :title, :description, :category, :zone
acts_as_votable
is_impressionable
before_destroy { |record| record.tags.destroy_all if record.tags.any? }
end
Then add a column photo_counts to your zones table and use it like this
<% #zones.each do |zone| %>
<%= zone.photo_counts %>
<%end%>
This avoids multiple requests to the DB.Look into this Railscast for more info.
Hope it helps!
simply
<%= #photos.select{|photo| photo.zone.name == "Zone1"}.count%>
Related
I want to create an invoice in rails. Invoice can have items and each item will have quantity, tax & price. It's a typical invoice we see everyday.
In order to create an invoice what is the best approach.
What is the common model for invoice and items?
I know Items will be a separate model. But how can we have one view for invoice, which creates both the invoice and items added to it?
What I mean is, Inside a new invoice page, there will be list of the clients, and list of the items , But here i'm not sure how to make the association when i create invoice. Is there any good example that i can follow ?
Please I'd appreciate some Help. Or even just a walk through of the steps i need to follow in order to accomplish that...
Here's my basic ERD
Quite a broad question, here's what I'd do:
#app/models/invoice.rb
class Invoice < ActiveRecord::Base
belongs_to :user
has_many :line_items
has_many :items, through: :line_items
accepts_nested_attributes_for :line_items
end
#app/models/line_item.rb
class LineItem < ActiveRecord::Base
belongs_to :invoice
belongs_to :item
end
#app/models/item.rb
class Item < ActiveRecord::Base
belongs_to :company
has_many :line_items
has_many :invoices, through: :line_items
end
--
#app/models/user.rb
class User < ActiveRecord::Base
has_many :invoices
end
This will be the base level "invoice" association structure - your clients/users can be built on top of it.
Your routes etc can be as follows:
#config/routes.rb
resources :invoices
#app/controllers/invoices_controller.rb
class InvoicesController < ApplicationController
def new
#invoice = current_user.invoices.new
#invoice.line_items.build
end
def create
#invoice = current_user.invoices.new invoice_params
#invoice.save
end
end
Then your view will be something like this:
#app/views/invoices/new.html.erb
<%= form_for #invoice do |f| %>
<%= f.fields_for :line_items do |l| %>
<%= f.text_field :quantity %>
<%= f.collection_select :product_id, Product.all, :id, :name %>
<% end %>
<%= f.submit %>
<% end %>
This would create the corresponding #invoice, with which you'll be able to call as follows:
#user.invoices.first
Apart from this, I don't have anywhere enough specific information to help specifically
May I recommend using the payday gem? I have created invoice models in the past applications and I'll tell you what, it can get pretty tricky sometimes depending on the type of application you're building. But the reason I like using this gem besides the convenience factor is that it can also render your invoices as a customizable PDF.
It makes adding items to the invoice a breeze as well, for example from their GitHub page:
invoice = Payday::Invoice.new(:invoice_number => 12)
invoice.line_items << Payday::LineItem.new(:price => 20, :quantity => 5, :description => "Pants")
invoice.line_items << Payday::LineItem.new(:price => 10, :quantity => 3, :description => "Shirts")
invoice.line_items << Payday::LineItem.new(:price => 5, :quantity => 200, :description => "Hats")
invoice.render_pdf_to_file("/path/to_file.pdf")
I write:
<%= Chat.find_by(id: 6).chatusers.each { |chat_user| chat_user.user.inspect } %>
(There are three models: Chat, Chatuser, User)
Chat.find_by(id: 6).chatusers returns collection of table "chats_users" and this is fine working.
But i can not get model user by each element of collection in method "each".
So, question is why each not working to get relative model "user" or how to resolve my task by each or another way.
class Chat < ActiveRecord::Base
has_many :chatusers
has_many :users, through: :chatusers
class Chatuser < ActiveRecord::Base
self.table_name = "chats_users"
belongs_to :chat
belongs_to :user
validates :chat_id, presence: true
validates :user_id, presence: true
end
class User < ActiveRecord::Base
has_many :chats, class_name: "Chatuser"
Thanks.
Resolving
Solution is using another style of ruby-html writing:
<% Chat.find_by(id: 6).chatusers.each do |chat_user| %>
<%= chat_user.user.inspect %>
<% end %>
Thanks for Ruby on Rails Talk
If i understood you question right, and you want to get all users for a chat, then this would do it:
Chat.find(6).users
Resolving
Solution is using another style of ruby-html writing:
<% Chat.find_by(id: 6).chatusers.each do |chat_user| %>
<%= chat_user.user.inspect %>
<% end %>
Thanks for Ruby on Rails Talk
I have 3 models source.rb belongs to category.rb and feed_entry.rb belongs to source.rb.
I need to display feed_entries in category
Category name
FeedEntry 1
FeedEntry 2
FeedEntry 3
Now it looks like this
class CategoriesController < ApplicationController
def show
#category = Category.find(params[:id])
#sources = #category.sources.all
end
end
show.html.erb
<%= #category.name %></h4>
<% #sources.each do |source| %>
<% source.feed_entries.each do |feed_entry| %>
<%= link_to feed_entry.name, feed_entry %>
<%= feed_entry.source.title %>
<% end %>
<% end %>
this is very slow
I use mongoid 4, rails 4
Models
class Category
include Mongoid::Document
field :name, type: String
has_many :sources, dependent: :destroy
end
class FeedEntry
include Mongoid::Document
field :name, type: String
belongs_to :source, touch: true
validates :source_id, presence: true
end
class Source
include Mongoid::Document
field :title, type: String
has_many :feed_entries, dependent: :destroy
belongs_to :category, touch: true
end
Some thinks to know :
Never use .all, unless you know size of result data. Always use pagination or limit.
When you have a loop like your each in view, this will call queries like this :
Give me a category
Give me its sources
Give me feed entries for source 1
Give me feed entries for source 2
....
You should eagler load your association like this :
#sources = #category.sources.limit(20).includes(:feed_entries)
It will to theses queries :
Give me a category
Give me its sources
Give me feed entries for theses sources
If you don't want any information about categories (like I think), you should add a relation to your model :
Class Category
has_many :sources
has_many :feed_entries, :through => :sources
end
Then call in your controller
#feed_entries = #category.feed_entries
This will do only ONE query :
Give me category
Give me the feed entries of the category
That's it !
I found a solution:
In Category.rb add feed_entries
class Category
def feed_entries
FeedEntry.in(source_id: sources.map(&:id))
end
end
and in show.html.erb
<% #category.feed_entries.includes(:source).each do |feed_entry| %>
<%= link_to feed_entry.name, feed_entry %>
<%= feed_entry.source.title %>
<% end %>
I would like to synchronize a has_many association by foreign key. It seems I have to write custom code to do this. Is there any Rails / Active Record magic / Gem to achieve this? Specifically, I'd like to synchronize a join-table where the pairs of foreign keys should be unique.
class Food < ActiveRecord::Base
has_many :food_tags, :dependent=>:destroy, :inverse_of => :food
accepts_nested_attributes_for :food_tags, :allow_destroy => true
end
class FoodTag < ActiveRecord::Base
belongs_to :tag, :inverse_of=>:food_tags
belongs_to :food, :inverse_of=>:food_tags
end
class Tag < ActiveRecord::Base
has_many :food_tags, :dependent=>:destroy, :inverse_of=>:tag
has_many :foods, :through=>:food_tags
end
For my form with nested attributes (or my JSON API), I'd really like to omit the FoodTag id and use the tag_id to synchronize when updating a food.
I want to submit this on update to show that the tag is set or cleared
# this one is set
food[food_tag_attributes][0][tag_id] = 2114
food[food_tag_attributes][0][_destroy] = false
# this one is cleared
food[food_tag_attributes][1][tag_id] = 2116
food[food_tag_attributes][1][_destroy] = true
Instead, I have to submit this for update:
# this one is set
food[food_tag_attributes][0][id] = 109293
food[food_tag_attributes][0][tag_id] = 2114
food[food_tag_attributes][0][_destroy] = false
# this one is cleared
food[food_tag_attributes][0][id] = 109294
food[food_tag_attributes][1][tag_id] = 2116
food[food_tag_attributes][1][_destroy] = true
This pushes a burden to the client to know the IDs of the food tag records instead of just being able to Set or Clear tags based on the tag id.
Can this be done easily? I'm sure I could write a before_save filter on Food, but it seems like there should be a reasonably generic solution.
There is an option called index: for fields_for in the view helper. You can set the index as your foreign_key. Then instead of sequential or some arbitrary numbers, your foreign_key will be used as the key to refer to your object.
EDIT:
<%= form_for #person do |person_form| %>
<%= person_form.text_field :name %>
<% #person.addresses.each do |address| %>
<%= person_form.fields_for address, **index**: address.id do |address_form|%>
<%= address_form.text_field :city %>
<% end %>
<% end %>
<% end %>
How do I search with associations and through with sunspot?
class StaticController < ApplicationController
def search
#search = Sunspot.search Business, Service do
fulltext params[:q]
paginate :per_page => 10
order_by_geodist(:location, *Geocoder.coordinates(params[:loc]))
end
#biz = #search.results
end
class Business < ActiveRecord::Base
attr_accessible :name
has_many :services, :through => :professionals
searchable do
text :name #name in business column
# how to do I get the services?
end
end
class Service < ActiveRecord::Base
attr_accessible :service
belongs_to :professional
end
class Professional < ActiveRecord::Base
belongs_to :business
has_many :services, as: :servicable
end
In the view, I have this (lots of looping)
<%= #biz.each do |b| %>
<%= b.name %>
<!-- looping through professionals model -->
<% b.professionals.each do |prof| %>
<!-- looping through services model -->
<% prof.services.each do |s| %>
<%= s.service %>
<% end %>
<% end %>
<% end %>
This works if I search for a name that is within the business model, but what if I'm searching through a term that's in the Service model? It won't display correctly because my view is only coming from the business side. How do I make it so the business name will pop up if I search through Service model?
Thanks
You will need to make additional indexes for the associated models in the calling model to make this happen. For example:
class Business < ActiveRecord::Base
attr_accessible :name
has_many :services, :through => :professionals
searchable do
text :name #name in business column
text :services do # this one for full text search
services.map(&:service).compact.join(" ")
end
string :services , :multiple => true do #this one for exact searches
services.map(&:service).compact
end
end
end
After that you can do queries like:
Bussines.search do
with(:services, "some_service")
end.execute.results
Now you no longer have to do join on mysql tables to fetch data. You can just fetch data from the solr. This is one of biggest advantages of solr.
I hope this makes it clear. Fell free to drop a comment if you need more details.