I have a store application with a Product scaffold and I want to enable categories and pages that show each category of products.
My product model has a "category" attribute and I use the link_to helper to create links to each category.
In my products controller I added a method called index_by_category(cat):
def index_by_category(cat)
#products_by_category = Product.where(category: cat)
end
I'm trying to iterate #products_by_category in a view I created with the corresponding name (product/index_by_category.html.erb) just like the regular index method do. For some reason it render me the regular index method of products which shows ALL of them, even though the URL is:
http://localhost:3000/products?index_by_category=Food
This is what I did in my route.rb file:
get 'products/index_by_category'
I'm newbie to Rails development so if I did something which is wrong from the roots and the rails approach to the problem should be entirely different I also be happy to know for the sake of learning.
You are doing things a bit wrong. Try to write your controller like this:
def index_by_category
#products_by_category = Product.where(category: params[:category])
end
And update your route
get 'products/category/:category', to: 'products#index_by_category
Then visit
http://localhost:3000/products/category/Food
UPDATE
if you really want to use index method for both cases you could do that by modifying it to something like this
def index
if params[:category]
#products = Product.where(category: params[:category])
else
#products = Product.all
end
end
and then just visit
http://localhost:3000/products?category=Food
Related
Im making this site for clothes where I have different categories and I have a resource named "Items" for managing every clothing (since I've read somewhere, one controller per resource).
So for example, if I want to display jackets, I have a route like this:
get '/jackets', to: 'items#index', page: 'jackets'
And the controller has an index action that has a switch statement with all the different possibilities inside (I'm using scopes here):
def index
case params[:page]
# Women / Clothing
when "clothing"
#items = Item.clothing
when "beachwear"
#items = Item.beachwear
when "coats"
#items = Item.coats
Is this the right way do do it? Or should I make a single action for each kind of category that I have?
Thanks in advance and sorry for my bad english
Edit: I have something close to 100 categories.
Are Item.clothing, Item.coats, etc, scopes or? How have you implemented your model?
Why not just do something like:
def index
#items = Item.where(category: params[:category])
end
(provided, of course, that you add a category field in your Item model)
note that I changed params[:page] to params[:category] for semantic reasons
I have a post controller that allows you to select a profession. I also have a work controller that has a list of professions stored seperated by commas. Eg:
Post has a row called profession, and only allows you to choose 1.
Work has a row called profession that are stored like this: business, law, accounting.
What I would like to do is once you save your post, take you to a page that shows work where Post profession is equal to Work profession. (Only relevant work show)
How would I go about doing this?
This sounds like what you're trying to do.
posts_controller.rb
def create
#post = Post.create(post_params)
if #post.save
redirect_to some_other_path(post_id: #post.id)
else
# handle error
end
end
some_controller.rb
def some_action
#post = Post.find(params[:post_id])
#works = Work.where("profession like ?", "%#{#post.profession}%")
end
Since you're using Postgres, you can use like which will match patterns within a field. This is more of a search functionality than a way of associating records. So if you have a Post that has a profession of "market", the like would match "market" and "marketing".
It might prove to be cleaner and easier to have Profession be a separate model. Post could belong_to, and Work could have_many.
My rails app has a database set.
def index
#clubs = Club.all
end
This is my controller.
If i type in my Index.html.erb
<% #clubs.each do |club| %>
<%= club.name %>
<% end %>
I get all the names of my database show in my index view.
What if I just want to pick one or just a couple?
Thru the rails console i can by typing c=Club.find(1) 1 by default takes id=1.
So how can i just display several ID's and not all one the database in the same index.html.erb.
thanks anyway!
Try this:
Let us consider that params[:ids] contains all the ids that belong to the records you want to get.
def index
#clubs = Club.where(id: params[:ids])
end
Fix
The straightforward answer here is to recommend you look at the ActiveRecord methods you can call in your controller; specifically .where:
#app/controllers/clubs_controller.rb
Class ClubsController < ApplicationController
def index
#clubs = Club.where column: "value"
end
end
This will populate the #clubs instance variable with only the records which match that particular condition. Remember, it's your Rails app, so you can do what you want with it.
Of course, it's recommended you stick with convention, but there's nothing stopping you populating specific data into your #clubs variable
--
RESTful
As someone mentioned, you shouldn't be including "filtered" records in an index action. Although I don't agree with this idea personally, the fact remains that Rails is designed to favour convention over configuration - meaning you should really leave the index action as showing all the records
You may wish to create a collection-specific action:
#config/routes.rb
resources :clubs do
collection do
get :best #-> domain.com/clubs/best
end
end
#app/controllers/clubs_controller.rb
Class ClubsController < ApplicationController
def best
#clubs = Club.where attribute: "value"
render "index"
end
end
There are several ways to select a specific record or group of records from the database. For example, you can get a single club with:
#club = Club.find(x)
where x is the id of the club. Then in your view (the .html.erb file), you can simply access the #club object's attributes.
You can also cast a wider net:
#disco_clubs = Club.where(type: "disco") # returns an ActiveRecord Relation
#disco_clubs = Club.where(type: "disco").to_a # returns an array
And then you can iterate over them in the same manner you do in your index.html.erb. Rails has a rich interface for querying the database. Check it out here.
Also note that individual records - such as those selected with the find method - are more commonly used with the show action, which is for displaying a single record. Of course, that's for generic CRUD applications. It't not a hard rule.
change
def index
#clubs = Club.all
end
to this
def index
#clubs = Club.find(insert_a_number_that_is_the_id_of_the_club_you_want)
end
Querying your database is a complex thing and gives you a ton of options so that you can get EXACTLY what you want and put it into your #clubs variable. I suggest reading this part of the rails guide
It should also be noted that if you're only going to query your database for one record then change #clubs to #club so you know what to expect.
A complete rails beginner here.
How do I go about handling a query string in rails?
For example for:
www.something.com/movie?sort=title
For implementing the the view in the haml file, how can I make it so that clicking on Movie title will send that query string,
And more importantly how do I handle it. Where should I implement the function which can access that query string using :params .
I have been on this for more than a day now and could not understand whether that query string will call a controller function or a module from helper.
I hope I was clear enough about the question.
Any help will be appreciated.
PS:- there is a movie table with title as one of its column.
Not sure I really understand what you want. Does this suit you?
link_to "My Link", movie_index_path(sort: :title)
Then access param with params[:sort] ?
(Accord movie_index_path with your routes configuration)
Since your question is not focused let me assume part of your problem.
Assumptions
You have a controller name movies_controller.rb in app/controllers/
folder You have a model named movie.rb in app/models folder
Then you should tell Rails to route requests with path /movies to movies_controller.rb. This can be done by adding the below lines in config/routes.rb
resources :movies
The if you call www.something.com/movies this will invoke the method index in movies_controller.rb. So you should write some code to display movies here.
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
end
Then you should use app/views/movies/index.haml file to display the movies. There give a link to sort the movies by title.
link_to "Sort by title", movies_path(:sort=>"title")
No when click on the link the user will reach the same index method with params now. You can get the sort value like below.
params[:sort]
SO to support sorting you need to change the controller code little bit.
class MoviesController < ApplicationController
def index
if params[:sort]
#movies = Movie.order('#{params[:sort]} ASC')
else
#movies = Movie.all
end
end
end
I strongly suggest you to go through the http://guides.rubyonrails.org/index.html before asking question.
What's the best way to construct a where clause using Rails ActiveRecord? For instance, let's say I have a controller action that returns a list of blog posts:
def index
#posts = Post.all
end
Now, let's say I want to be able to pass in a url parameter so that this controller action only returns posts by a specific author:
def index
author_id = params[:author_id]
if author_id.nil?
#posts = Post.all
else
#posts = Post.where("author = ?", author_id)
end
end
This doesn't feel very DRY to me. If I were to add ordering or pagination or worse yet, more optional URL query string params to filter by, this controller action would get very complicated.
How about:
def index
author_id = params[:author_id]
#posts = Post.scoped
#post = #post.where(:author_id => author_id) if author_id.present?
#post = #post.where(:some_other_condition => some_other_value) if some_other_value.present?
end
Post.scoped is essentially a lazy loaded equivalent to Post.all (since Post.all returns an array
immediately, while Post.scoped just returns a relation object). This query won't be executed until
you actually try to iterate over it in the view (by calling .each).
Mmmh, the best approach you want to use can be to spread this in 2 actions
def index
#post = Post.all
end
def get
#post = Post.where("author=?", params[:author_id])
end
IMHO it has more sense if you think about a RESTful API, index means to list all and get (or show) to fetch the requested one and show it!
This question is pretty old but it still comes up high in google in 2019, and also some earlier answers have been deprecated, so I thought I would share a possible solution.
In the model introduce some scopes with a test for the existence of the parameter passed:
class Post
scope :where_author_ids, ->(ids){ where(author_id: ids.split(‘,’)) if ids }
scope :where_topic_ids, ->(ids){ where(topic_id: ids.split(‘,’)) if ids }
Then in the controller you can just put as many filters in as you wish e.g:
def list
#posts = Post.where_author_ids(params[:author_ids])
.where_topic_ids(params[:topic_ids])
.where_other_condition_ids(params[:other_condition_ids])
.order(:created_at)
The parameter can then be a single value or a comma separated list of values, both work fine.
If a param doesn’t exist it simply skips that where clause and doesn’t filter for that particular criteria. If the param exists but its value is an empty string then it will ‘filter out’ everything.
This solution won’t suit every circumstance of course. If you have a view page with several filters on, but upon first opening you want to show all your data instead of no data until you press a ‘submit’ button or similar (as this controller would) then you will have to tweak it slightly.
I’ve had a go at SQL injecting this and rails seems to do a good job of keeping everything secure as far as I can see.
You should model url using nested resources. The expected url would be /authors/1/posts. Think of authors as resources. Read about nested resources in this guide: http://guides.rubyonrails.org/routing.html (scroll to 2.7 - Nested Resources).
Would something like this work?
def get
raise "Bad parameters...why are you doing this?" unless params[:filter].is_a?(Hash)
#post = Post.where(params[:filter])
end
Then you can do something like:
?filter[author_id]=1&filter[post_date]=... etc.