skip to Main Content

I’m a bit new to rails. so I’m tryna do a craigslist clone. so far I have implemented all the categories and the subcategories. I came upon this error when I attempted to SEO my url links so that it could be like this craigslist-clone/c/community/activities/3 where ‘community’ is the parent category and ‘activities’ being the subcategory and therefore ‘3’ being the post at which.

now I can click on each parent category error-less. the only time I get an error is when I click on a subcategory and the error is as follows:

No route matches {:action=>"show", :controller=>"categories", :url=>""}, missing required keys: [:url]

  <% category.subcategories.limit(10).each do |subcategory| %>
               <div class= "subcat"><%= link_to subcategory.name, show_category_path(subcategory.url) %></div>
           <%end%> 

           </div>

My categories_controller :

class CategoriesController < ApplicationController
  before_action :set_category, only: [:show, :edit, :update, :destroy]

  # GET /categories
  # GET /categories.json
  def index
    @categories = Category.all
  end

  # GET /categories/1
  # GET /categories/1.json
  def show
    category_ids = @category.subcategories.ids
    category_ids << @category.id
    @posts = Post.where(category_id: category_ids)

  end

  # GET /categories/new
  def new
    @category = Category.new
  end

  # GET /categories/1/edit
  def edit
  end

  # POST /categories
  # POST /categories.json
  def create
    @category = Category.new(category_params)

    respond_to do |format|
      if @category.save
        format.html { redirect_to @category, notice: 'Category was successfully created.' }
        format.json { render :show, status: :created, location: @category }
      else
        format.html { render :new }
        format.json { render json: @category.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /categories/1
  # PATCH/PUT /categories/1.json
  def update
    respond_to do |format|
      if @category.update(category_params)
        format.html { redirect_to @category, notice: 'Category was successfully updated.' }
        format.json { render :show, status: :ok, location: @category }
      else
        format.html { render :edit }
        format.json { render json: @category.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /categories/1
  # DELETE /categories/1.json
  def destroy
    @category.destroy
    respond_to do |format|
      format.html { redirect_to categories_url, notice: 'Category was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_category
      @category = Category.find_by_url(params[:url])
    end


    # Only allow a list of trusted parameters through.
    def category_params
      params.fetch(:category, {})
    end
end

My home.html.erb is :

            <div class="row">
            <% @categories.each do |category| %>
            <div class="col-4 mb-4 category-box">
            <p class="h6"><strong><%= link_to category.name, show_category_path(category.url), class: "text-dark" %></strong></p>

            <% category.subcategories.limit(10).each do |subcategory| %>
                <div class= "subcat"><%= link_to subcategory.name, show_category_path(subcategory.url) %></div>
            <%end%> 

            </div>
            <% end %> 

routes.rb

  devise_for :accounts
  resources :posts
  resources :categories, except:[:show]
  get "c/:url" => "categories#show", as: :show_category
  post "message/send" => "public#send_enquiry_to_user", as: :send_enquiry
  get "/scams" => "public#scams", as: :scams
  get "/terms" => "public#terms", as: :terms
  get "/safety" => "public#safety", as: :safety
  get "/faqs" => "public#faqs", as: :faqs
   devise_scope :account do
     get "/accounts/sign_out" => "devise/sessions#destroy"
   end
  root to: "public#home"
end```

my category.rb Model :

class Category < ApplicationRecord
    belongs_to :parent, class_name:"Category", optional: true
    has_many :subcategories, class_name:"Category", foreign_key: :parent_id, dependent: :destroy
    has_many :posts
end

my Categories table :

  create_table "categories", force: :cascade do |t|
    t.string "name"
    t.string "url"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "parent_id"
  end

I just feel like I’ve reached a dead end, any help or any recommendation of a resource I may need to read to be able to overcome this problem is highly appreciated. Thank you!

3

Answers


  1. One of you subcategory seems to be having a blank URL.

    <% category.subcategories.limit(10).each do |subcategory| %>
      <% next if subcategory.url.blank? %>
      <div class= "subcat"><%= link_to subcategory.name, show_category_path(subcategory.url) %></div>
    <% end %> 
    
    Login or Signup to reply.
  2. You have defined a custom route like this:

    get "c/:url" => "categories#show", as: :show_category
    

    Therefore you need to explicitly pass a url key to the route method, like this:

    show_category_path(url: category.url)
    

    You could also, alternatively, override the named route parameter instead of using a bound parameter. In other words, you could define the route using something like this:

    resources :categories, path: "c", only: :show, param: :url
    

    This generates the following route, and your original code would work fine with it:

    category GET     /c/:url(.:format)    categories#show
    
    Login or Signup to reply.
  3. So i have also run into this kind of problem before and you may want to change your resource route with a :path option and it might help.

    devise_for :accounts
      resources :posts
      resources :categories, path: "c", except:[:show] do
       get "/:url" => "categories#show", as: :show_category
      end
    
      post "message/send" => "public#send_enquiry_to_user", as: :send_enquiry
      get "/scams" => "public#scams", as: :scams
      get "/terms" => "public#terms", as: :terms
      get "/safety" => "public#safety", as: :safety
      get "/faqs" => "public#faqs", as: :faqs
       devise_scope :account do
         get "/accounts/sign_out" => "devise/sessions#destroy"
       end
      root to: "public#home"
    end
    

    or you could also just pass explicitly pass the :url to your route helper like show_category_path(url: category.url)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search