I'm creating a marketplace app where sellers can list items to sell. I want to create a category dropdown so customers can select a category to shop.
In my listing model, I have a 'category' field. When a user selects a category, I want the view to filter listings from that category.
In my routes.rb:
get '/listings/c/:category' => 'listings#category', as: 'category'
To create the category menu - in my index.html.erb:
<%= Listing.uniq.pluck(:category).each do |category| %>
<%= link_to category, category_path(category: category) %>
<% end %>
In my listings controller:
def category
#category = category
#listings = Listing.not_expired.where(:category => #category)
end
category.html.erb:
<% #listings.each do |listing| %>
#some html
<% end %>
The homepage category menu shows up. The routes are created. But when I click on the category, the url such as listings/c/necklaces gives me the stack level too deep error.
FYI "Stack Level Too Deep" basically means you have an infinite loop in your code somewhere
--
From what I can see, the error will be here:
def category
#category = category
With this code, you're basically invoking the category method again, which in turn will invoke the category method etc, in a never-ending cycle. This will prevent your application from being able to run without reloading itself in infinite recursion.
You should change it to:
def category
#category = params[:category]
#listings = Listing.not_expired.where(:category => #category)
end
However, a much more refined way would be:
#app/models/category.rb
class Category < ActiveRecord::Base
has_many :listings do
def not_available
#your not available method here
end
end
end
#app/models/listing.rb
class Listing < ActiveRecord::Base
belongs_to :category
end
#app/controllers/your_controller.rb
def category
#category = Category.find params[:categpry]
#listings = #category.listings.not_available
Related
I want my trade page to show a list of every Item that a user has added to their cart, and I'm having trouble understanding why this implementation is giving me a NoMethodError
So in the #show action of my TradesController I have a trade_ids variable that contains an array of added items returned by $redis.smembers current_user_trade. I then use this to perform a lookup on the id of each item, and loop through the instance variable in my view.
My Trades Controller:
class TradesController < ApplicationController
def show
trade_ids = $redis.smembers current_user_trade
#trade_items = Item.find(trade_ids)
end
def add
$redis.sadd current_user_trade, params[:item_id]
render json: current_user.trade_count, status: 200
end
def remove
$redis.srem current_user_trade, params[:item_id]
render json: current_user.trade_count, status: 200
end
private
def current_user_trade
"trade#{current_user.id}"
end
end
Here's the method I'm using to add items to current_user_trade:
class Item < ActiveRecord::Base
extend FriendlyId
friendly_id :slug, use: [:slugged, :finders]
def slug
[artist.parameterize, title.parameterize].join("-")
end
def trade_action(current_user_id)
if $redis.sismember "trade#{current_user_id}", id
"Remove from"
else
"Add to"
end
end
end
My routes:
resource :trade, only: [:show] do
put 'add/:item_id', to: 'trades#add', as: :add_to
put 'remove/:item_id', to: 'trades#remove', as: :remove_from
end
And then in my trades view I've got a basic:
<% #trade_items.each do |item| %>
<p><%= item.title %></p>
etc
<% end %>
My initial thought is that this had something to do with the fact that I've been using FriendlyId for slug generation. But according to FriendlyId's doc, adding :finders to the slug declaration in my Item model should reenable lookups by id. But it's not.
I also tried refactoring this so that it used my Items :slug, but that too was to no avail.
Fixed it. Turns out it was cached. I switched from storing item_id to item_slug halfway through, and needed to run redis-cli flushall to get it to store and access the right data.
I am learning Ruby on Rails and have a search form set up and its working. On the pins index view I can search for pins(posts) by their title. However if I wanted to search by Username which is not in the pins table and display the results on the Pins index page how would I do this? How do I access an attribute from a different table? (Sorry for the newbie attempt at explaining my issue)
Pins controller
def index
#pins = Pin.search(params[:term])
end
Pin Model
def self.search(term)
if term
where('description LIKE ?', "%#{term}%")
else
order('id DESC')
end
end
_search.html.erb
<%= form_tag(pins_path, method: :get) do %>
<%= text_field_tag :term, params[:term] %>
<%= submit_tag 'Search', description: nil %>
<% end %>
Assuming you have set up something like
class User < ApplicationRecord
has_many :pins
# the username is stored in the attribute 'username'
end
class Pin < ApplicationRecord
belongs_to :user
end
you may do the following
# PinsController
def index
terms = params[:term]
username = params[:username]
#pins = Pin
#pins = #pins.where("description LIKE '%?%'", term) if term
#pins = #pins.includes(:user).where("users.username LIKE '%?%'", username) if username
# you may want to sort by id anyway
#pins = #pins.order('id DESC')
end
Note that I put the code straight to the controller for brevity. You may refactor this to use your search method in pin model.
# _search.html.erb
<%= form_tag(pins_path, method: :get) do %>
<%= text_field_tag :term, params[:term] %>
<%= text_field_tag :username, params[:username] %>
<%= submit_tag 'Search', description: nil %>
<% end %>
In case you want to do some more searching and filtering you may have a look at the ransack gem although I think you're going the right path in trying to figure this out yourself.
Although those railscasts episodes are from the past I think they are applicable to the current rails versions. Anyway one can get the point from them
http://railscasts.com/episodes/37-simple-search-form
http://railscasts.com/episodes/111-advanced-search-form
http://railscasts.com/episodes/240-search-sort-paginate-with-ajax
Another good resource is gorails.com (not affiliate in any way!!). I can highly recommend them as a resource for learning
Provided you have an association between User and Pin
class User
has_many :pins
end
class Pin
belongs_to :user
end
You can join :user from Pin and set conditions on the association:
Pin.joins(:user).where('users.username ? AND awesome = ?', 'Max', true)
# or the preferred method
Pin.joins(:user).where(user: { username: 'Max', awesome: true })
Note that we use users.username and not user.username when writing a SQL string you're specifying the table name - not the association.
To search for pins based on the username you could do:
def self.by_username(term)
joins(:user).where('users.username LIKE ?', "%#{term}%")
end
How do I find and manage subcategories? (the find_subcategory method i'd defined does not seem to work.)
class CategoriesController < ApplicationController
before_action :find_category, only: [:show]
def index
#categories = Category.order(:name)
end
def show
end
private
def find_category
#category = Category.find(params[:id])
end
def find_subcategory
#subcategory = Category.children.find(params[:parent_id])
end
end
I'm using the acts_as_tree gem, which has:
root = Category.create("name" => "root")
child1 = root.children.create("name" => "child1")
subchild1 = child1.children.create("name" => "subchild1")
root.parent # => nil
child1.parent # => root
root.children # => [child1]
root.children.first.children.first # => subchild1
It's not clear what you want your find_subcategory method to do, but if you want it to find all subcategories of the category with id in params[:id], then change it to
def find_subcategories
#subcategories = Category.where(:parent_id => params[:parent_id]).all
end
In your original you're just looking for a single subcategory, and if you just want a single category you might as well just load it from it's id.
I know you accepted the answer, but I've done this before and so it might be beneficial to explain how we did it:
Firstly, we used the ancestry gem. I think acts_as_tree is deprecated -- acts_as_tree is better than ancestry, I forgot why we used it now - ancestry works in a very similar way (parent column, child methods, etc).
I'll explain our implementation with ancestry - hopefully it will give you some ideas for acts_as_tree:
#app/models/category.rb
class Category < ActiveRecord::Base
has_ancestry #-> enables the ancestry gem (in your case it should be "acts_as_tree"
end
This will allow you to populate the ancestry (in your case parent_id) column in your categories model, and (most importantly) gives you the ability to call the child methods attached to objects in the model:
#category.parent
#category.children
... etc.
--
The important thing to note here is how we're able to call the child objects (which would be subcategories in your case).
Your method is to create separate objects and have them inherit from each other. The beauty of ancestry / acts_as_tree is their added methods.
Any object with the correct parent ids can call their "children" as associative data:
In our case, we were able to associate all the objects using the ancetry column. This is slightly trickier than acts_as_tree because you have to provide the entire hierarchy in the column (which is lame), nonetheless the result is still the same:
#app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
end
#app/views/categories/index.html.erb
<%= render #categories %>
#app/views/categories/_category.html.erb
<%= category.name %>
<%= render category.children if category.has_children? %>
This will output the sub categories for you:
How do I find and manage subcategories
You can do it like this:
#subcategories = Category.where parent_id: #category.id
or if you have your ancestry set up properly, you should be able to use the following:
#config/routes.rb
resources :categories
#app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def show
#category = Category.find params[:id]
end
end
This will allow you to use:
#app/views/categories/show.html.erb
<% #category.children.each do |subcategory| %>
<%= subcategory.name %>
<% end %>
I have a Slider model in my project and it has a lot of polymorphic associations with other model like Product, Manufacturer, Article and etc.
So, when I use 'show' action with one of the models I also show related Slider. It's ok. But sometimes I need to show Slider with 'index' action.
What is the best way to link some of the sliders to actions, not to other models?
UPDATE
routes
resources :products, :articles, :industries, :manufacturers, only: [:index, :show]
Product controller
class ProductsController < ApplicationController
load_resource
# GET /products
# GET /products.json
def index
#catalog = Product.by_type_and_manufacturer
end
# GET /products/1
# GET /products/1.json
def show
#page_slider = #product.slider
end
end
So in 'show' action I just use product.slider to get related Slider instance. But I want to show another slider for all products by index action.
In that case, what you're trying to do is not possible. You cannot create a relation to a controller action. What you need to do is link the relation's controller action, rather than trying to create a relation to the controller action. A model can only be related to another model (you cannot has_many index, show, delete, etc...)- In other words, call up the data for the relation, and link to that relation's controller action in the view.
example:
#Models:
class Page < ActiveRecord::Base
has_many :sliders
end
class Slider < ActiveRecord::Base
belongs_to :page
end
#Controllers
class PagesController < ApplicationController
def index
#pages = Page.all # lists all pages
end
def show
#page = Page.find(params[:id]) # simplified, this will probably make use of strong params in your actual code
#sliders = #page.sliders # all sliders related to the page
end
# if you would like to show a page that just has all sliders for a specific page and not the page itself...
def show_page_sliders # you will have to create a route and view for this manually
#page = Page.find(params[:id]) # simplified, this will probably make use of strong params in your actual code
#sliders = #page.sliders # all sliders related to the page
# note that this controller action is identical to the show action, because the data we're going to need is the same- the difference comes in the view
end
end
class SlidersController < ApplicationController
def index
#sliders = Slider.all
end
def show
#slider = Slider.find(params[:id])
end
end
# Views
# page#index
<% #pages.each do |p| %>
...
page listing code goes here. if you want to list the sliders for each page on the index...
<% p.sliders.each do |s| %>
...
individual slider info goes here
...
<% end %>
...
<% end %>
# pages#show
<%= #page.name %>
<%= #page.content %> <!-- or whatever data you have for page -->
# since here we are showing a singular page, we can just use our #page instance variable to list out the sliders
<% #page.sliders do |s| %>
...
Slider listing code goes here
...
<% end %>
# pages#show_sliders
<!-- this is identical to the page#show view, minus the actual page info, and with the addition of a link back to the parent page -->
<%= link_to "Back to page", page(s.page_id) %>
<% #page.sliders do |s| %>
...
Slider listing code goes here
<!-- you can link to any path from the slider listing -->
<%= link_to "Show", slider(s.id) %>
<%= link_to "Edit", edit_slider_path(s.id) %>
<%= link_to "Delete", delete_slider_path(s.id) %>
...
<% end %>
#######################UPDATE#############################
# to define one slider per controller action
class PagesController < ApplicationController
def index
#pages = Page.all
# you need to add a "controller_action" column to your Slider model
#slider = Slider.find_where(controller_action: "pages#index")
end
def show
#page = Page.find(params[:id])
#slider = Slider.find_where(controller_action: "pages#show")
end
# etc ...
I am new to Ruby on rails. I've created basic demo apps by tutorial learning by examples.
Application have three model User,Village and article
Village has many users, Village has many articles, user and article belongs to village
I work , migration work fine
when iam in http://0.0.0.0:3000/villages/1 , i display all user that belong to village 1
My question is how display in all user in village one this url http://0.0.0.0:3000/villages/1/users
To do that you need to add the url to the routes.rb file under the config folder.
Add line like below
resources :villages do
member do
get '/user', to: 'villages#show'
end
end
I am assuming that your villages show action is the one that has all the user details displayed.
routes.rb
resources :villages do
member do
get :users, :articles
end
end
In villages_controller
def users
#village = Village.find(params[:id])
#values = #village.users.paginate(page: params[:page])
render 'show_data'
end
def articles
#village = Village.find(params[:id])
#values = #village.articles.paginate(page: params[:page])
render 'show_data'
end
In show_data.html.erb
<% if #values.any? %>
<% #values.each do |value| %>
<%= value.name %>
<% end %>
<%end%>
<%= will_paginate %>