how to use order by in rails model - ruby-on-rails

Consider I have a index controller which will display all category and sub category
My index controller has
#categories = Category.where(status: true)
category.rb
has_many :sub_categories
here is my sub_category
sub_category.rb
belongs_to :category
In my view I have
<% #categories.each do |category| %>
<%= category.name %>
<% category.sub_categories.each do |sub_category| %>
<%= sub_category.name %>
<% end %>
<% end %>
My sub_category has status(true, false) I need to display only the sub_category with the status as true
How can I do this.

By using where, i.e. category.sub_categories.where(status: true):
<% #categories.each do |category| %>
<%= category.name %>
<% category.sub_categories.where(status: true).each do |sub_category| %>
<%= sub_category.name %>
<% end %>
<% end %>
Or even better to return only what's required, just select the #categories that have subcategories with status = true.
For this update your controller's action code where you have #categories defined:
# controller
#categories = Category.includes(:sub_categories).where('sub_categories.status = ?', true)
Then in your view:
<% #categories.each do |category| %>
<%= category.name %>
<% category.sub_categories.each do |sub_category| %>
<%= sub_category.name %>
<% end %>
<% end %>

I would recommend to use scope in your app. In SubCategory model add scope :active, where(active: true) and then use category.sub_categories.active.each ...

Related

How can show value through association?

I'm trying to show a phone number when customer contact has it
Table:
|customers|
|id| |name|
1 Zidane
2 Mourinho
3 Guardiola
4 Ferguson
|contacts|
|id| |customer_id| |name| |phone|
1 1 Muller
2 1 Alaba 9872147
3 2 Aubameyang 2323234
4 3 Dante
5 3 Robben
6 3 Lewandoski 2343256
7 4 Ribery
Controller:
def index
#customers = Customer.all
end
Model:
class Customer < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :customer
end
View:
<% #customers.each do |customer| %>
<%= customer.name %>
<% customer.contacts(:conditions=>['phone>0']).each do |contact| %>
<%= contact.name %>
<%= contact.phone %>
<% end %>
<% end %>
Also tried:
<% #customers.each do |customer| %>
<%= customer.name %>
<% customer.contacts.each do |contact| %>
<%= contact.name %>
<%= contact.phone(:all,:conditions=>['phone>0']). %>
<% end %>
<% end %>
Also tried but is only getting the first contact:
<%= customer.contacts.first(1).map { |c| c.phone } %>
Also tried but is only getting the last contact:
<%= customer.contacts.last(1).map { |c| c.phone } %>
I want this as result:
|customer| |name_contact| |phone|
Zidane Alaba 9872147
CR7 Aubameyang 2323234
Guardiola Lewandoski 2343256
Ferguson Ribery
Something like below can work
<% customer.contacts.all {|c| c.phone.present?}.each do |contact| %>
Full snippet
<% #customers.each do |customer| %>
<%= customer.name %>
<% customer.contacts.all {|c| c.phone.present?}.each do |contact| %>
<%= contact.name %>
<%= contact.phone %>
<% end %>
<% end %>

Best way to define global objects in Ruby on Rails

I have an app that has two models Category and Product
Products belong to categories.
I have created a navbar dropdown that requires an #category and #product object to be available across the entire app (the navbar is shown on every page of the application.)
What I can't work out is the best place to put these basic definitions without defining them multiple times in every page definition.
I need to define the following:
#category = Category.all
#products = #category.products.all
The navbar loop will then look something like this.
<% #category.each do |c| %>
<%= c.name %>
<% #products.each do |p| %>
<% link_to product_path(p) do %>
<%= p.name %>
<% end %>
<% end %>
<% end %>
I am a bit of a rails newbie so I am sure there are some errors in here but any help would be much appreciated!
If you need them in every single page of app, you can set them in ApplicationController's before_filter:
class ApplicationController
before_filter :get_categories
# ...
private
def get_categories
#categories = Category.includes(:products)
end
end
then, you can write in your view:
<% #categories.each do |category| %>
<%= category.name %>
<% category.products.each do |product| %>
<%= link_to p.name, p %>
<% end %>
<% end %>
I also fixed some other errors and convention incompatibilities.
The following code is incorrect.
#category = Category.all
#products = #category.products.all
This code assigns to #categories all the categories, then it attempts to fetch the products. It will not work, unless you have defined a products class method in the Category model. But I don't think so, otherwise you will just have to call Product.all.
Moreover, in the code below, you are trying to display the list of products per category, which definitely don't work with the two assignments before. According to what you are trying to achieve, you can't pre-assign the #products, because you want the products for a specific category.
Let's inline everything into the code.
<% Category.all.each do |category| %>
<%= category.name %>
<% category.products.each do |product| %>
<%= link_to product_path(product) do %>
<%= product.name %>
<% end %>
<% end %>
<% end %>
Next step is to make the code a little bit more performant, giving you need it everywhere.
<% Category.select(:id, :name).each do |category| %>
<%= category.name %>
<% category.products.select(:id, :name).each do |product| %>
<%= link_to product_path(product) do %>
<%= product.name %>
<% end %>
<% end %>
<% end %>
You could use pluck, but it will return an array and it will require a little bit more manipulation. However, it's way more performant.
<% Category.pluck(:id, :name).each do |category_id, category_name| %>
<%= category_name %>
<% Product.where(category_id: category_id).pluck(:id, :name).each do |product_id, product_name| %>
<%= link_to product_name, product_path(id: product_id) %>
<% end %>
<% end %>
It's not a good idea to chain all those methods inside a view, let's extract some code into the model.
class Category
def self.simple_listing
order(:name).pluck(:id, :name)
end
end
class Product
def self.simple_category_listing(category_id)
where(category_id: category_id).order(:name).pluck(:id, :name)
end
end
<% Category.simple_listing.each do |category_id, category_name| %>
<%= category_name %>
<% Product.simple_category_listing(category_id).each do |product_id, product_name| %>
<%= link_to product_name, product_path(id: product_id) %>
<% end %>
<% end %>
You can leave all this code into the view, or extract it into a partial. You don't even need to add a controller before filter, or make it "global". The code is self-contained, does not pollute the name space with instance variables, and it can easily be placed whenever you need it.

Rails element if first time appearance

I have a model Post with :mark, :text
I have a list with my post
<% #posts.each do |p| %>
# todo
<% if p.mark? %>
<%= p.mark %> <%= sweet_thing(p.text) %>
<% else %>
<%= sweet_thing(p.text) %>
<% end %>
<% end %>
I need to show p.mark name instead #todo where p.mark first time appearance.
Final txt example:
Audi
Audi, text-text-text-text.
Audi, text-text-text-text.
Audi, text-text-text-text.
Ford
Ford, text-text-text-text.
Ford, text-text-text-text.
Ford, text-text-text-text.
Ford, text-text-text-text.
UPDATE
My txt render in controller
def txt_receiver
#posts = Post.where("created_at >= ?", 7.days.ago.utc).find(:all, order: "mark, LOWER(post)")
render "txt_for_newspapper", formats: ["text"]
end
An obvious solution is to keep track of seen marks.
<% seen_marks = {} %>
<% #posts.each do |p| %>
<% unless seen_marks[p.mark] %>
<%= p.mark %>
<% seen_marks[p.mark] = true %>
<% end %>
# rest of your code
<% end %>
A better solution (I think) involves grouping posts by their mark and then outputting in groups. But I'm not sure whether it will match your logic regarding missing marks.
<% #posts.group_by(&:mark).each do |mark, posts| %>
<%= mark %>
<% posts.each do |p| %>
<%= p.mark if mark %> <%= sweet_thing(p.text) %>
<% end %>
<% end %>

How to show parent and child in view with will paginate?

I'm having trouble showing my view correctly. I have this as my code right now:
<% for store in #stores %>
<% store.name %>
<% #stores.products.each do |p| %>
<% p.name %>
<% end %>
<% end %>
def index
#stores = Store.paginate(:page => params[:page], :per_page => 20)
end
But end up with the error:
undefined method `products'
I'm trying to show a store and then all of its products, repeating this on the same page as much as possible e.g:
Store1
Product1
Product2
Store2
Product1
Product2
Product3
Product4
How can I do this?
Instead of <% #stores.products.each do |p| %> I think you mean <% store.products.each do |p| %>:
Also, do you not mean to have <%= on the store.name and p.name lines?
<% for store in #stores %>
<%= store.name %>
<% store.products.each do |p| %>
<%= p.name %>
<% end %>
<% end %>
Shouldn't that be store.products inside the loop, where you're accessing store?
<% for store in #stores %>
<%= store.name %>
<% store.products.each do |p| %>
<%= p.name %>
<% end %>
<% end %>
And = is added to the output lines. <%=

Nested output with related models

I have a model Category and a model Weblink. Category has_many Weblink and Weblink belongs_to Category. Now I want to show all categories in a view and within a category all weblinks belonging to that category, something link this:
<ul>
<% #categories.each do |category| %>
<%= category.category_name %>
<% #weblinks.each do |weblink| %>
<%= weblink.category_name link_to weblink.link_name, weblink.link_url %>
<% end %>
<% end %>
In the controller I have:
#categories = Category.all
#weblinks = Weblink.all
This shows every category and within every category all weblinks, instead of just the ones which belong to the specific category. How can I fix this?
Your view code should look like this
<% #categories.each do |category| %>
<%= category.name >
<% category.weblinks.each do |weblink| %>
<%= link_to weblink.name, weblink.link_url %>
<% end -%>
<% end -%>
It your controller, when querying for all the categories you should also include the weblinks model, something like this:
#categories = Category.all(:include => :weblinks)
Scope the inner loop to the outer category using the macro you get with has_many:
<% #categories.each do |category| %>
<%= category.category_name %>
<% category.weblinks.each do |weblink| %>
<%= link_to weblink.link_name, weblink.link_url %>
<% end %>
<% end %>

Resources