Почему я не могу создать статью ни с одной категорией?

#ruby-on-rails #ruby

#ruby-on-rails #ruby

Вопрос:

Я новичок в RoR, и я работаю над приложением Blog и внедряю категории для статей. Но у меня проблема — когда я создаю любую статью с некоторыми категориями («спорт», «фильм» или любой другой) Я получаю ошибки проверки

  - Category must exist
 - Category can't be blank
  

Но у меня есть рабочий выпадающий список или категории (этот помощник):

   def categories
    category =
      ["Sport",
      "Movie",
      "Art",
      "Nature",
      "Exotic"]
    category.each do |categ|
      my_category = "#{categ}"
    end
    return category
  end
  

И вот фрагмент кода моего файла article.new.html.erb:

   <p>
    <%= f.label :category %><br>
    <%= f.select :category, categories,
        prompt: "Choose your category" %>
  </p>
  

Также вот моя схема БД, где присутствуют поля категорий:

   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.string "pic"
    t.string "photo_file_name"
    t.string "photo_content_type"
    t.bigint "photo_file_size"
    t.datetime "photo_updated_at"
    t.string "music_file_name"
    t.string "music_content_type"
    t.bigint "music_file_size"
    t.datetime "music_updated_at"
    t.string "movie_file_name"
    t.string "movie_content_type"
    t.bigint "movie_file_size"
    t.datetime "movie_updated_at"
    t.string "category_id"
  end

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

  create_table "comments", force: :cascade do |t|
    t.string "commenter"
    t.text "body"
    t.bigint "article_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["article_id"], name: "index_comments_on_article_id"
  end

  create_table "subscribers", force: :cascade do |t|
    t.string "f_name"
    t.string "l_name"
    t.string "email"
    t.string "country"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "users", force: :cascade do |t|
    t.string "userid"
    t.string "email"
    t.string "password_digest"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.boolean "admin", default: false
  end

  add_foreign_key "comments", "articles"
end
  

И вот мои модели:

 class Article < ApplicationRecord
  belongs_to :category
  has_many :comments, dependent: :destroy
  validates :title, presence: true, length: {minimum: 3}
  validates :text, presence: true, length: {minimum: 3}
  validates :category_id, presence: true
end

class Category < ApplicationRecord
  has_many :articles
end
  

Также это мой контроллер статей:

 class ArticlesController < ApplicationController
before_action :admin_authorize, :except => [:index, :show, :search]

  def index
    @articles = Article.includes(:category).order("created_at DESC")
    if params[:category].blank?
      @articles = Article.all.order("created_at DESC")
    else
      @category_id = Category.find_by(name: params[:category]).id
      @articles = Article.where(category_id: @category_id).order("created_at DESC")
    end
  end

  def new
    @article = Article.new
    @categories = Category.all.map{|c| [c.name, c.id]}
  end

  def show
    @article = Article.find(params[:id])
  end

  def create
    @article = Article.new(article_params)
    @article.category_id = params[:category_id]

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

  def edit
    @article = Article.find(params[:id])
    @categories = Category.all.map{|c| [ c.name, c.id ] }
  end

  def search
    if params[:search].blank?
      @articles = Article.all
    else
      @articles = Article.search(params)
    end
  end

  def update
    @article = Article.find(params[:id])
    @article.category_id = params[:category_id]
    if @article.update(article_params)
      redirect_to @article
    else
      render 'edit'
    end
  end

  def destroy
    @article = Article.find(params[:id])
    @article.destroy
    redirect_to articles_path
  end

private
  def article_params
    params.require(:article).permit(:title, :text, :search, :music, :movie, :photo)
  end

  def find_article
    @article = Article.find(params[:id])
  end
end
  

Заранее спасибо!!

Комментарии:

1. Эти категории существуют в базе данных, верно?

2. Да, я добавил их через консоль

3. @OrkoElvis Посмотрите журналы сервера, возможно, вам не хватает некоторых обязательных параметров.

4. с помощью консоли?

Ответ №1:

Вы забыли category_id в своих разрешенных параметрах:

 def article_params
  params.require(:article).permit(:title, :text, :search, :music, :movie, :photo, :category_id)
end
  

Вам также необходимо изменить свой помощник по выбору на отправку, category_id а не category в запросе POST.
Теперь, с помощью вашего categories помощника, вы не отправляете никакого идентификатора категории в select выпадающем списке, только некоторые имена «category», которые не привязаны ни к каким Category экземплярам.

Вы можете исправить это select следующим образом и удалить своего помощника:

 <p>
  <%= f.label :category %><br>
  <%= f.select :category_id, Category.all.collect{|c| [c.name, c.id]},
    prompt: "Choose your category" %>
</p>
  

Комментарии:

1. @OrkoElvis Да, вы правы! Вы не отправляете идентификатор категории в select раскрывающемся списке. Я обновил свой ответ.

2. Все то же самое (

3. @OrkoElvis Если у вас их нет Category в db, у вас всегда будут эти ошибки. Как говорится, Category должно существовать для создания Article из-за ассоциации belongs_to :category

4. Как я мог бы добавить их в db?

5. @OrkoElvis Запустите rails console в своем терминале и добавьте туда несколько категорий: Category.create(name: "My name", desc: "Whatever blah blah")