Dan
Dan

Reputation: 1

No route matches [PATCH] "/users/1/articles" error on Ruby on Rails

I'm very very new to this, and I'm trying to implement a to-do-list which allows use of tags with user authentication. When updating the task, I get a routing error which states No route matches [PATCH] "/users/1/articles". I suspect it's because I didn't pass the article ID when updating the article. Could anyone please help guide me on how to solve this? Any advice will be greatly appreciated thank you!

Routes from the error page

user_article_path   GET /users/:user_id/articles/:id(.:format)  
articles#show

PATCH   /users/:user_id/articles/:id(.:format)  
articles#update

PUT /users/:user_id/articles/:id(.:format)  
articles#update

DELETE  /users/:user_id/articles/:id(.:format)  
articles#destroy

Routes.rb

Rails.application.routes.draw do
  get 'sessions/new'
  get 'welcome/index'
  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'

  resources :users do
      resources :articles 
  end
  get 'tags/:tag', to: 'articles#index', as: :tag, :constraints  => { :tag => /[^\/]+/ }

  root 'welcome#index'
end

article.rb


class Article < ApplicationRecord
attr_accessor :content, :name, :tag_list
   before_create :downcase_fields
has_many :taggings , dependent: :destroy
has_many :tags, through: :taggings, dependent: :destroy 
 belongs_to :user    
 validates :user_id, presence: true
 validates :title, presence: true,
                   length: { minimum: 1}
  def self.tagged_with(name)
   Tag.find_by_name!(name).articles
  end


   def downcase_fields
      self.title.downcase
   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

def self.search(term)
  if term
    where('title LIKE ?', "%#{term}%").order('id DESC')
  else
    order('id DESC') 
  end
end
end

articles_controller

class ArticlesController < ApplicationController
  before_action :correct_user

  def index
      @user = User.find(params[:user_id])
      @articles = @user.articles.search(params[:term])
#    if params[:tag]
 #     @articles =  @user.articles.tagged_with(params[:tag])
 #   else
 #     @articles =  @user.articles.all
 #   end
  end

    def show
        @user = User.find(params[:user_id])
    @article = @user.articles.find(params[:id])
  end
 def new
      @user = User.find(params[:user_id])
  @article = @user.articles.new
end

def edit
      @user = User.find(params[:user_id])
  @article = @user.articles.find(params[:id])
end

def create
  @user = User.find(params[:user_id])
  @article = @user.articles.new(article_params)

  if @article.save
    redirect_to user_articles_url
  else
    render 'new'
  end
end

def update
   @user = User.find(params[:user_id])
  @article = @user.articles.find(params[:id])

  if @article.update(article_params)
    redirect_to user_articles_path
  else
    render 'edit'
  end
end

def destroy
  @user = User.find(params[:user_id])
  @article = @user.articles.find(params[:id])
  @article.destroy

  redirect_to user_articles_path
end
private
  def article_params
    params.require(:article).permit(:title, :text, :tag_list, :term)
  end


    # Confirms a logged_in user_
    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end

    # Confirms the correct user
    def correct_user
      @user = User.find(params[:user_id])
      redirect_to(root_url) unless current_user?(@user)
    end
end

db.schema.rb

ActiveRecord::Schema.define(version: 2019_01_27_093653) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "articles", force: :cascade do |t|
    t.string "title"
    t.text "text"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "user_id"
    t.index ["user_id"], name: "index_articles_on_user_id"
  end

  create_table "taggings", force: :cascade do |t|
    t.bigint "tag_id"
    t.bigint "article_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "user_id"
    t.index ["article_id"], name: "index_taggings_on_article_id"
    t.index ["tag_id"], name: "index_taggings_on_tag_id"
    t.index ["user_id"], name: "index_taggings_on_user_id"
  end

  create_table "tags", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "password_digest"
    t.string "remember_digest"
    t.index ["email"], name: "index_users_on_email", unique: true
  end

  add_foreign_key "articles", "users"
  add_foreign_key "taggings", "articles"
  add_foreign_key "taggings", "tags"
  add_foreign_key "taggings", "users"
end

User controller

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update]
  before_action :correct_user,   only: [:edit, :update]

  def show
    @user = User.find(params[:id])
          redirect_to user_articles_path(@user)

  end

  def new
    @user = User.new
  end

  def index
    @users = User.paginate(page: params[:page])
  end

  def create
    @user = User.new(user_params)
    if @user.save
      log_in @user
      flash[:success] = "Welcome to the To-Do-Manager!"
      redirect_to user_articles_path(@user)
    else
      render 'new'
    end
  end

   def edit
    @user = User.find(params[:id])
  end

   def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

_form.html.erb(Create and update share the same form)


<%= form_with model: @article,url: user_articles_path(@user), local: true do |form| %>

  <% if @article.errors.any? %>
    <div id="error_explanation">
      <h2>
        <%= pluralize(@article.errors.count, "error") %> prohibited
        this article from being saved:
      </h2>
      <ul>
        <% @article.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <p>
    <%= form.label :Task %><br>
    <%= form.text_field :title %>
  </p>

  <p>
    <%= form.label :Deadline %><br>
    <%= form.text_area :text %>
  </p>

  <p>
    <%= form.label :tag_list, "Tags (separated by commas)" %><br />
    <%= form.text_field :tag_list %>
  </p>

  <p>
    <%= form.submit %>
  </p>

<% end %>

Upvotes: 0

Views: 1259

Answers (2)

arieljuod
arieljuod

Reputation: 15838

You routes requires two parameters: the user (:user_id) and the article (:id), you are only passing the user user_articles_path(@user) and also using the plural form, and that route does not exists with that HTTP method.

You have to use url: user_article_path(@user,@article) (or you can use the shortcut version url: [@user, @article]).

Upvotes: 0

Sovalina
Sovalina

Reputation: 5609

Your user article path should be singular according to your routes:

<%= form_with model: @article, url: user_article_path(@user), local: true do |form| %>

Upvotes: 1

Related Questions