Prashin Jeevaganth
Prashin Jeevaganth

Reputation: 1343

no route matches leading to ActionController UrlGenerationError

I have created a ToDoList based off Hartl's tutorial, and following a video and worded tutorial to add a tagging system. I have followed till Section 10, where they asked me to modify my new.html.erb file to the code as shown on the source. To improvise for structural differences in code, I would edit some other files, like in this case, my micropost_form partial instead. Occasionally, I alternated between the code in the video and code in the worded tutorial because some of them would produce error messages or would not produce the required functionality. Here are the files that I think are involved in this question.

_micropost_form.html.erb(The filling up form that would be displayed on the user's home page)

<%= simple_form_for @micropost do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.label :content %><br />
    <%= f.text_area :content, placeholder: "Add new task..." %>
  </div>
  <div class="field">
    <%= f.label :tag_list, "Tags (separated by commas)" %><br />
    <%= f.text_field :tag_list %> 
  </div>
  <%= f.submit "Add Task", class: "btn btn-primary" %>
<% end %>

micropost.html.erb(for showing the individual micro posts)

<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, user_path(micropost.user) %></span>
  <span class="content"><%= micropost.content %></span>
  <p><small>Tags: <%= raw micropost.tags.map(&:name).map { |t| link_to t, tag_path(t) }.join(', ') %></small</p>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
    <% if current_user?(micropost.user) %>
      <%= link_to "Done", micropost_path(micropost), method: :delete, data: { confirm: "Keep up the good work!" } %>
    <% end %>
  </span>
</li>

routes.rb

Rails.application.routes.draw do
  resources :users
  resources :microposts          

  get    '/about',   to: 'static_pages#about'
  get    '/contact', to: 'static_pages#contact'
  get    '/signup',  to: 'users#new'
  post    '/signup',  to: 'users#create'
  get    '/login',    to: 'sessions#new'
  post   '/login',    to: 'sessions#create'
  delete '/logout',   to: 'sessions#destroy'
  get   '/users/admin',     to: 'users#admin'

  get 'tags/:tag', to: 'microposts#index', as: :tag

  root   'static_pages#home'
end

micropost_controller

class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]
  before_action :correct_user,   only: :destroy


  def index
    params[:tag] ? @microposts = Micropost.tagged_with(params[:tag]) : @microposts = Micropost.all
  end


  def show
    @micropost = Micropost.find(params[:id])
  end

  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end

  def destroy
    @micropost.destroy
    flash[:success] = "You have deleted a task!"
    redirect_to request.referrer || root_url
  end

  private

    def micropost_params
      params.require(:micropost).permit(:content, :tag_list, :tag, 
        {tag_ids: [] }, :tag_ids)
    end

    def correct_user
      @micropost = current_user.microposts.find_by(id: params[:id])
      redirect_to root_url if @micropost.nil?
    end
end

Micropost model

class Micropost < ApplicationRecord
  belongs_to :user
  has_many :taggings
  has_many :tags, through: :taggings
  default_scope -> { order(created_at: :desc) }
  validates :user_id, presence: true
  validates :content, presence: true, length: {maximum: 140 }
  attr_accessor :tag_list



  def self.tagged_with(name)
    Tag.find_by!(name: name).microposts
  end

  def self.tag_counts
    Tag.select('tags.*, count(taggings.tag_id) as count')
    .joins(:taggings).group('taggings.tag_id')
  end

  def tag_list
    tags.map(&:name).join(', ')
  end

  def tag_list=(names)
    self.tags = names.split(',').map do |n|
      Tag.where(name: n.strip).first_or_create!
    end
  end
end

Tag model

class Tag < ApplicationRecord
    attr_accessor :name
  has_many :taggings
  has_many :microposts, through: :taggings
end

static_pages controller

class StaticPagesController < ApplicationController
  def home
    if logged_in?
      @micropost  = current_user.microposts.build
      @feed_items = current_user.feed.paginate(page: params[:page])
    end
  end

  def help
  end

  def about
  end

  def contact
  end
end

feed.html.erb

<% if @feed_items.any? %>
  <ol class="microposts">
    <%= render @feed_items %>
  </ol>
  <%= will_paginate @feed_items %>
<% end %>

I got the following error

ActionController::UrlGenerationError in StaticPages#home
No route matches {:action=>"index", :controller=>"microposts", :tag=>nil}, missing required keys: [:tag]

Error highlighted

app/views/microposts/_micropost.html.erb:5:in `block in _app_views_microposts__micropost_html_erb___3891111682689684005_70324923859580'
app/views/microposts/_micropost.html.erb:5:in `map'
app/views/microposts/_micropost.html.erb:5:in `_app_views_microposts__micropost_html_erb___3891111682689684005_70324923859580'
app/views/shared/_feed.html.erb:3:in `_app_views_shared__feed_html_erb__3168328449514417483_70324923896060'
app/views/static_pages/home.html.erb:13:in `_app_views_static_pages_home_html_erb__3511776991923566869_70324898321240'

Can anyone suggest what might be wrong here? Please let me know if more information is needed.

Update: I have implemented some of the changes provided by the answer below, but still has not understood why :tag is not detected, and why the code in red is actually highlighted.

Upvotes: 1

Views: 1734

Answers (2)

Prashin Jeevaganth
Prashin Jeevaganth

Reputation: 1343

I actually found the cause of the problem to be quite simple. After running rails console, it seems like my db:seed wasn't even raked properly, causing my tags to have nil names and causing me to be unable to find the route. Looking further into Rails console is adding nil instead of values to solve my seed adding problem, I realised I have added attr_accessor, forgetting that normal attributes should be added via the command line into the Migration instead of writing into the Model directly. Removing it according to the post updates my database and the code works.

Upvotes: 1

Noel
Noel

Reputation: 996

ActionController::UrlGenerationError in StaticPages#home
No route matches {:action=>"index", :controller=>"microposts", :tag=>nil}, missing required keys: [:tag]

The problem is you don't have an index route for your microposts.

Rails.application.routes.draw do
  root   'static_pages#home'
  get    '/readme',    to: 'static_pages#readme'
  get    '/about',   to: 'static_pages#about'
  get    '/contact', to: 'static_pages#contact'
  get    '/signup',  to: 'users#new'
  post    '/signup',  to: 'users#create'
  get    '/login',    to: 'sessions#new'
  post   '/login',    to: 'sessions#create'
  delete '/logout',   to: 'sessions#destroy'
  get   '/users/admin',     to: 'users#admin'
  resources :users
  resources :microposts,          only: [:create, :destroy] #Here's the problem
  get 'tags/:tag', to: 'microposts#index', as: :tag
end

change to:

resources :microposts, only: [:index, :create, :destroy]

EDIT:

Another problem is

if logged_in?
  @micropost  = current_user.microposts.build #this just returns a new 1
  @feed_items = current_user.feed.paginate(page: params[:page])
end

You probably want something like:

if logged_in?
  @microposts  = current_user.microposts
  @feed_items = Micropost.all.paginate(page: params[:page])
end

This will give you all the user's microposts. Then you iterate through them in your views.

Upvotes: 1

Related Questions