mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-30 18:47:51 +00:00 
			
		
		
		
	feat: Category API to handle linked categories and parent-sub categories (#4879)
This commit is contained in:
		| @@ -8,10 +8,20 @@ class Api::V1::Accounts::CategoriesController < Api::V1::Accounts::BaseControlle | |||||||
|  |  | ||||||
|   def create |   def create | ||||||
|     @category = @portal.categories.create!(category_params) |     @category = @portal.categories.create!(category_params) | ||||||
|  |     @category.related_categories << related_categories_records | ||||||
|  |     render json: { error: @category.errors.messages }, status: :unprocessable_entity and return unless @category.valid? | ||||||
|  |  | ||||||
|  |     @category.save! | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   def show; end | ||||||
|  |  | ||||||
|   def update |   def update | ||||||
|     @category.update!(category_params) |     @category.update!(category_params) | ||||||
|  |     @category.related_categories = related_categories_records if related_categories_records.any? | ||||||
|  |     render json: { error: @category.errors.messages }, status: :unprocessable_entity and return unless @category.valid? | ||||||
|  |  | ||||||
|  |     @category.save! | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   def destroy |   def destroy | ||||||
| @@ -29,9 +39,13 @@ class Api::V1::Accounts::CategoriesController < Api::V1::Accounts::BaseControlle | |||||||
|     @portal ||= Current.account.portals.find_by(slug: params[:portal_id]) |     @portal ||= Current.account.portals.find_by(slug: params[:portal_id]) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   def related_categories_records | ||||||
|  |     @portal.categories.where(id: params[:category][:related_category_ids]) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   def category_params |   def category_params | ||||||
|     params.require(:category).permit( |     params.require(:category).permit( | ||||||
|       :name, :description, :position, :slug, :locale |       :name, :description, :position, :slug, :locale, :parent_category_id, :linked_category_id | ||||||
|     ) |     ) | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -2,28 +2,56 @@ | |||||||
| # | # | ||||||
| # Table name: categories | # Table name: categories | ||||||
| # | # | ||||||
| #  id                        :bigint           not null, primary key | #  id                 :bigint           not null, primary key | ||||||
| #  description               :text | #  description        :text | ||||||
| #  locale                    :string           default("en") | #  locale             :string           default("en") | ||||||
| #  name                      :string | #  name               :string | ||||||
| #  position                  :integer | #  position           :integer | ||||||
| #  slug                      :string           not null | #  slug               :string           not null | ||||||
| #  created_at                :datetime         not null | #  created_at         :datetime         not null | ||||||
| #  updated_at                :datetime         not null | #  updated_at         :datetime         not null | ||||||
| #  account_id                :integer          not null | #  account_id         :integer          not null | ||||||
| #  portal_id                 :integer          not null | #  linked_category_id :bigint | ||||||
|  | #  parent_category_id :bigint | ||||||
|  | #  portal_id          :integer          not null | ||||||
| # | # | ||||||
| # Indexes | # Indexes | ||||||
| # | # | ||||||
|  | #  index_categories_on_linked_category_id             (linked_category_id) | ||||||
| #  index_categories_on_locale                         (locale) | #  index_categories_on_locale                         (locale) | ||||||
| #  index_categories_on_locale_and_account_id          (locale,account_id) | #  index_categories_on_locale_and_account_id          (locale,account_id) | ||||||
|  | #  index_categories_on_parent_category_id             (parent_category_id) | ||||||
| #  index_categories_on_slug_and_locale_and_portal_id  (slug,locale,portal_id) UNIQUE | #  index_categories_on_slug_and_locale_and_portal_id  (slug,locale,portal_id) UNIQUE | ||||||
| # | # | ||||||
|  | # Foreign Keys | ||||||
|  | # | ||||||
|  | #  fk_rails_...  (linked_category_id => categories.id) | ||||||
|  | #  fk_rails_...  (parent_category_id => categories.id) | ||||||
|  | # | ||||||
| class Category < ApplicationRecord | class Category < ApplicationRecord | ||||||
|   belongs_to :account |   belongs_to :account | ||||||
|   belongs_to :portal |   belongs_to :portal | ||||||
|   has_many :folders, dependent: :destroy_async |   has_many :folders, dependent: :destroy_async | ||||||
|   has_many :articles, dependent: :nullify |   has_many :articles, dependent: :nullify | ||||||
|  |   has_many :category_related_categories, | ||||||
|  |            class_name: :RelatedCategory, | ||||||
|  |            dependent: :destroy_async | ||||||
|  |   has_many :related_categories, | ||||||
|  |            through: :category_related_categories, | ||||||
|  |            class_name: :Category, | ||||||
|  |            dependent: :nullify | ||||||
|  |   has_many :sub_categories, | ||||||
|  |            class_name: :Category, | ||||||
|  |            foreign_key: :parent_category_id, | ||||||
|  |            dependent: :nullify, | ||||||
|  |            inverse_of: 'parent_category' | ||||||
|  |   has_many :linked_categories, | ||||||
|  |            class_name: :Category, | ||||||
|  |            foreign_key: :linked_category_id, | ||||||
|  |            dependent: :nullify, | ||||||
|  |            inverse_of: 'linked_category' | ||||||
|  |   belongs_to :parent_category, class_name: :Category, optional: true | ||||||
|  |   belongs_to :linked_category, class_name: :Category, optional: true | ||||||
|  |  | ||||||
|   before_validation :ensure_account_id |   before_validation :ensure_account_id | ||||||
|   validates :account_id, presence: true |   validates :account_id, presence: true | ||||||
| @@ -31,6 +59,7 @@ class Category < ApplicationRecord | |||||||
|   validates :name, presence: true |   validates :name, presence: true | ||||||
|   validates :locale, uniqueness: { scope: %i[slug portal_id], |   validates :locale, uniqueness: { scope: %i[slug portal_id], | ||||||
|                                    message: 'should be unique in the category and portal' } |                                    message: 'should be unique in the category and portal' } | ||||||
|  |   accepts_nested_attributes_for :related_categories | ||||||
|  |  | ||||||
|   scope :search_by_locale, ->(locale) { where(locale: locale) if locale.present? } |   scope :search_by_locale, ->(locale) { where(locale: locale) if locale.present? } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								app/models/related_category.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/models/related_category.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | # == Schema Information | ||||||
|  | # | ||||||
|  | # Table name: related_categories | ||||||
|  | # | ||||||
|  | #  id                 :bigint           not null, primary key | ||||||
|  | #  created_at         :datetime         not null | ||||||
|  | #  updated_at         :datetime         not null | ||||||
|  | #  category_id        :bigint | ||||||
|  | #  related_category_id :bigint | ||||||
|  | # | ||||||
|  | # Indexes | ||||||
|  | # | ||||||
|  | #  index_related_categories_on_category_id_and_related_category_id  (category_id,related_category_id) UNIQUE | ||||||
|  | #  index_related_categories_on_related_category_id_and_category_id  (related_category_id,category_id) UNIQUE | ||||||
|  | # | ||||||
|  | class RelatedCategory < ApplicationRecord | ||||||
|  |   belongs_to :related_category, class_name: 'Category' | ||||||
|  |   belongs_to :category, class_name: 'Category' | ||||||
|  | end | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | json.id category.id | ||||||
|  | json.name category.name | ||||||
|  | json.slug category.slug | ||||||
|  | json.locale category.locale | ||||||
|  | json.description category.description | ||||||
|  | json.position category.position | ||||||
|  | json.account_id category.account_id | ||||||
| @@ -5,3 +5,23 @@ json.locale category.locale | |||||||
| json.description category.description | json.description category.description | ||||||
| json.position category.position | json.position category.position | ||||||
| json.account_id category.account_id | json.account_id category.account_id | ||||||
|  |  | ||||||
|  | json.related_categories do | ||||||
|  |   if category.related_categories.any? | ||||||
|  |     json.array! category.related_categories.each do |related_category| | ||||||
|  |       json.partial! 'api/v1/accounts/categories/associated_category.json.jbuilder', category: related_category | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | if category.parent_category.present? | ||||||
|  |   json.parent_category do | ||||||
|  |     json.partial! 'api/v1/accounts/categories/associated_category.json.jbuilder', category: category.parent_category | ||||||
|  |   end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | if category.linked_category.present? | ||||||
|  |   json.linked_category do | ||||||
|  |     json.partial! 'api/v1/accounts/categories/associated_category.json.jbuilder', category: category.linked_category | ||||||
|  |   end | ||||||
|  | end | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								app/views/api/v1/accounts/categories/show.json.jbuilder
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/views/api/v1/accounts/categories/show.json.jbuilder
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | json.payload do | ||||||
|  |   json.partial! 'category', category: @category | ||||||
|  | end | ||||||
| @@ -159,9 +159,7 @@ Rails.application.routes.draw do | |||||||
|             member do |             member do | ||||||
|               post :archive |               post :archive | ||||||
|             end |             end | ||||||
|             resources :categories do |             resources :categories | ||||||
|               resources :folders |  | ||||||
|             end |  | ||||||
|             resources :articles |             resources :articles | ||||||
|           end |           end | ||||||
|         end |         end | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								db/migrate/20220623113405_add_parent_id_to_category.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								db/migrate/20220623113405_add_parent_id_to_category.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | class AddParentIdToCategory < ActiveRecord::Migration[6.1] | ||||||
|  |   def change | ||||||
|  |     add_reference :categories, :parent_category, foreign_key: { to_table: :categories } | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										12
									
								
								db/migrate/20220623113604_create_related_categories.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								db/migrate/20220623113604_create_related_categories.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | class CreateRelatedCategories < ActiveRecord::Migration[6.1] | ||||||
|  |   def change | ||||||
|  |     create_table :related_categories do |t| | ||||||
|  |       t.bigint :category_id | ||||||
|  |       t.bigint :related_category_id | ||||||
|  |       t.timestamps | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     add_index :related_categories, [:category_id, :related_category_id], unique: true | ||||||
|  |     add_index :related_categories, [:related_category_id, :category_id], unique: true | ||||||
|  |   end | ||||||
|  | end | ||||||
| @@ -0,0 +1,5 @@ | |||||||
|  | class AddLinkedCategoryIdToCategories < ActiveRecord::Migration[6.1] | ||||||
|  |   def change | ||||||
|  |     add_reference :categories, :linked_category, foreign_key: { to_table: :categories } | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										17
									
								
								db/schema.rb
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								db/schema.rb
									
									
									
									
									
								
							| @@ -10,7 +10,7 @@ | |||||||
| # | # | ||||||
| # It's strongly recommended that you check this file into your version control system. | # It's strongly recommended that you check this file into your version control system. | ||||||
|  |  | ||||||
| ActiveRecord::Schema.define(version: 2022_06_22_090344) do | ActiveRecord::Schema.define(version: 2022_06_27_135753) do | ||||||
|  |  | ||||||
|   # These are extensions that must be enabled in order to support this database |   # These are extensions that must be enabled in order to support this database | ||||||
|   enable_extension "pg_stat_statements" |   enable_extension "pg_stat_statements" | ||||||
| @@ -197,8 +197,12 @@ ActiveRecord::Schema.define(version: 2022_06_22_090344) do | |||||||
|     t.datetime "updated_at", precision: 6, null: false |     t.datetime "updated_at", precision: 6, null: false | ||||||
|     t.string "locale", default: "en" |     t.string "locale", default: "en" | ||||||
|     t.string "slug", null: false |     t.string "slug", null: false | ||||||
|  |     t.bigint "parent_category_id" | ||||||
|  |     t.bigint "linked_category_id" | ||||||
|  |     t.index ["linked_category_id"], name: "index_categories_on_linked_category_id" | ||||||
|     t.index ["locale", "account_id"], name: "index_categories_on_locale_and_account_id" |     t.index ["locale", "account_id"], name: "index_categories_on_locale_and_account_id" | ||||||
|     t.index ["locale"], name: "index_categories_on_locale" |     t.index ["locale"], name: "index_categories_on_locale" | ||||||
|  |     t.index ["parent_category_id"], name: "index_categories_on_parent_category_id" | ||||||
|     t.index ["slug", "locale", "portal_id"], name: "index_categories_on_slug_and_locale_and_portal_id", unique: true |     t.index ["slug", "locale", "portal_id"], name: "index_categories_on_slug_and_locale_and_portal_id", unique: true | ||||||
|   end |   end | ||||||
|  |  | ||||||
| @@ -683,6 +687,15 @@ ActiveRecord::Schema.define(version: 2022_06_22_090344) do | |||||||
|     t.index ["user_id"], name: "index_portals_members_on_user_id" |     t.index ["user_id"], name: "index_portals_members_on_user_id" | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   create_table "related_categories", force: :cascade do |t| | ||||||
|  |     t.bigint "category_id" | ||||||
|  |     t.bigint "related_category_id" | ||||||
|  |     t.datetime "created_at", precision: 6, null: false | ||||||
|  |     t.datetime "updated_at", precision: 6, null: false | ||||||
|  |     t.index ["category_id", "related_category_id"], name: "index_related_categories_on_category_id_and_related_category_id", unique: true | ||||||
|  |     t.index ["related_category_id", "category_id"], name: "index_related_categories_on_related_category_id_and_category_id", unique: true | ||||||
|  |   end | ||||||
|  |  | ||||||
|   create_table "reporting_events", force: :cascade do |t| |   create_table "reporting_events", force: :cascade do |t| | ||||||
|     t.string "name" |     t.string "name" | ||||||
|     t.float "value" |     t.float "value" | ||||||
| @@ -826,6 +839,8 @@ ActiveRecord::Schema.define(version: 2022_06_22_090344) do | |||||||
|   add_foreign_key "articles", "users", column: "author_id" |   add_foreign_key "articles", "users", column: "author_id" | ||||||
|   add_foreign_key "campaigns", "accounts", on_delete: :cascade |   add_foreign_key "campaigns", "accounts", on_delete: :cascade | ||||||
|   add_foreign_key "campaigns", "inboxes", on_delete: :cascade |   add_foreign_key "campaigns", "inboxes", on_delete: :cascade | ||||||
|  |   add_foreign_key "categories", "categories", column: "linked_category_id" | ||||||
|  |   add_foreign_key "categories", "categories", column: "parent_category_id" | ||||||
|   add_foreign_key "contact_inboxes", "contacts", on_delete: :cascade |   add_foreign_key "contact_inboxes", "contacts", on_delete: :cascade | ||||||
|   add_foreign_key "contact_inboxes", "inboxes", on_delete: :cascade |   add_foreign_key "contact_inboxes", "inboxes", on_delete: :cascade | ||||||
|   add_foreign_key "conversations", "campaigns", on_delete: :cascade |   add_foreign_key "conversations", "campaigns", on_delete: :cascade | ||||||
|   | |||||||
| @@ -5,6 +5,9 @@ RSpec.describe 'Api::V1::Accounts::Categories', type: :request do | |||||||
|   let(:agent) { create(:user, account: account, role: :agent) } |   let(:agent) { create(:user, account: account, role: :agent) } | ||||||
|   let!(:portal) { create(:portal, name: 'test_portal', account_id: account.id) } |   let!(:portal) { create(:portal, name: 'test_portal', account_id: account.id) } | ||||||
|   let!(:category) { create(:category, name: 'category', portal: portal, account_id: account.id, slug: 'category_slug') } |   let!(:category) { create(:category, name: 'category', portal: portal, account_id: account.id, slug: 'category_slug') } | ||||||
|  |   let!(:category_to_link) { create(:category, name: 'linked category', portal: portal, account_id: account.id, slug: 'linked_category_slug') } | ||||||
|  |   let!(:related_category_1) { create(:category, name: 'related category 1', portal: portal, account_id: account.id, slug: 'category_slug_1') } | ||||||
|  |   let!(:related_category_2) { create(:category, name: 'related category 2', portal: portal, account_id: account.id, slug: 'category_slug_2') } | ||||||
|  |  | ||||||
|   describe 'POST /api/v1/accounts/{account.id}/portals/{portal.slug}/categories' do |   describe 'POST /api/v1/accounts/{account.id}/portals/{portal.slug}/categories' do | ||||||
|     context 'when it is an unauthenticated user' do |     context 'when it is an unauthenticated user' do | ||||||
| @@ -15,23 +18,76 @@ RSpec.describe 'Api::V1::Accounts::Categories', type: :request do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     context 'when it is an authenticated user' do |     context 'when it is an authenticated user' do | ||||||
|       category_params = { |       let!(:category_params) do | ||||||
|         category: { |         { | ||||||
|           name: 'test_category', |           category: { | ||||||
|           description: 'test_description', |             name: 'test_category', | ||||||
|           position: 1, |             description: 'test_description', | ||||||
|           locale: 'es', |             position: 1, | ||||||
|           slug: 'test_category_1' |             locale: 'es', | ||||||
|  |             slug: 'test_category_1', | ||||||
|  |             parent_category_id: category.id, | ||||||
|  |             linked_category_id: category_to_link.id, | ||||||
|  |             related_category_ids: [related_category_1.id, related_category_2.id] | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|       } |       end | ||||||
|  |  | ||||||
|  |       let!(:category_params_2) do | ||||||
|  |         { | ||||||
|  |           category: { | ||||||
|  |             name: 'test_category_2', | ||||||
|  |             description: 'test_description_2', | ||||||
|  |             position: 1, | ||||||
|  |             locale: 'es', | ||||||
|  |             slug: 'test_category_2', | ||||||
|  |             parent_category_id: category.id, | ||||||
|  |             linked_category_id: category_to_link.id, | ||||||
|  |             related_category_ids: [related_category_1.id, related_category_2.id] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       end | ||||||
|  |  | ||||||
|       it 'creates category' do |       it 'creates category' do | ||||||
|         post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories", |         post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories", | ||||||
|              params: category_params, |              params: category_params, | ||||||
|              headers: agent.create_new_auth_token |              headers: agent.create_new_auth_token | ||||||
|         expect(response).to have_http_status(:success) |         expect(response).to have_http_status(:success) | ||||||
|  |  | ||||||
|         json_response = JSON.parse(response.body) |         json_response = JSON.parse(response.body) | ||||||
|         expect(json_response['payload']['name']).to eql('test_category') |  | ||||||
|  |         expect(json_response['payload']['related_categories'][0]['id']).to eql(related_category_1.id) | ||||||
|  |         expect(json_response['payload']['related_categories'][1]['id']).to eql(related_category_2.id) | ||||||
|  |         expect(json_response['payload']['parent_category']['id']).to eql(category.id) | ||||||
|  |         expect(json_response['payload']['linked_category']['id']).to eql(category_to_link.id) | ||||||
|  |         expect(category.reload.sub_category_ids).to eql([Category.last.id]) | ||||||
|  |         expect(category_to_link.reload.linked_category_ids).to eql([Category.last.id]) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       it 'creates multiple sub_categories under one parent_category' do | ||||||
|  |         post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories", | ||||||
|  |              params: category_params, | ||||||
|  |              headers: agent.create_new_auth_token | ||||||
|  |  | ||||||
|  |         post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories", | ||||||
|  |              params: category_params_2, | ||||||
|  |              headers: agent.create_new_auth_token | ||||||
|  |  | ||||||
|  |         expect(response).to have_http_status(:success) | ||||||
|  |         expect(category.reload.sub_category_ids).to eql(Category.last(2).pluck(:id)) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       it 'creates multiple linked_categories with one category' do | ||||||
|  |         post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories", | ||||||
|  |              params: category_params, | ||||||
|  |              headers: agent.create_new_auth_token | ||||||
|  |  | ||||||
|  |         post "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories", | ||||||
|  |              params: category_params_2, | ||||||
|  |              headers: agent.create_new_auth_token | ||||||
|  |  | ||||||
|  |         expect(response).to have_http_status(:success) | ||||||
|  |         expect(category_to_link.reload.linked_category_ids).to eql(Category.last(2).pluck(:id)) | ||||||
|       end |       end | ||||||
|  |  | ||||||
|       it 'will throw an error on locale, category_id uniqueness' do |       it 'will throw an error on locale, category_id uniqueness' do | ||||||
| @@ -81,18 +137,74 @@ RSpec.describe 'Api::V1::Accounts::Categories', type: :request do | |||||||
|           category: { |           category: { | ||||||
|             name: 'test_category_2', |             name: 'test_category_2', | ||||||
|             description: 'test_description', |             description: 'test_description', | ||||||
|             position: 1 |             position: 1, | ||||||
|  |             related_category_ids: [related_category_1.id], | ||||||
|  |             parent_category_id: related_category_2.id | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         expect(category.name).not_to eql(category_params[:category][:name]) |         expect(category.name).not_to eql(category_params[:category][:name]) | ||||||
|  |         expect(category.related_categories).to be_empty | ||||||
|  |         expect(category.parent_category).to be_nil | ||||||
|  |  | ||||||
|         put "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories/#{category.id}", |         put "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories/#{category.id}", | ||||||
|             params: category_params, |             params: category_params, | ||||||
|             headers: agent.create_new_auth_token |             headers: agent.create_new_auth_token | ||||||
|         expect(response).to have_http_status(:success) |  | ||||||
|         json_response = JSON.parse(response.body) |         json_response = JSON.parse(response.body) | ||||||
|  |  | ||||||
|         expect(json_response['payload']['name']).to eql(category_params[:category][:name]) |         expect(json_response['payload']['name']).to eql(category_params[:category][:name]) | ||||||
|  |         expect(json_response['payload']['related_categories'][0]['id']).to eql(related_category_1.id) | ||||||
|  |         expect(json_response['payload']['parent_category']['id']).to eql(related_category_2.id) | ||||||
|  |         expect(related_category_2.reload.sub_category_ids).to eql([category.id]) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       it 'updates related categories' do | ||||||
|  |         category_params = { | ||||||
|  |           category: { | ||||||
|  |             related_category_ids: [related_category_1.id] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         category.related_categories << related_category_2 | ||||||
|  |         category.save! | ||||||
|  |  | ||||||
|  |         expect(category.related_category_ids).to eq([related_category_2.id]) | ||||||
|  |  | ||||||
|  |         put "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories/#{category.id}", | ||||||
|  |             params: category_params, | ||||||
|  |             headers: agent.create_new_auth_token | ||||||
|  |  | ||||||
|  |         expect(response).to have_http_status(:success) | ||||||
|  |  | ||||||
|  |         json_response = JSON.parse(response.body) | ||||||
|  |  | ||||||
|  |         expect(json_response['payload']['name']).to eql(category.name) | ||||||
|  |         expect(json_response['payload']['related_categories'][0]['id']).to eql(related_category_1.id) | ||||||
|  |         expect(category.reload.related_category_ids).to eq([related_category_1.id]) | ||||||
|  |         expect(related_category_1.reload.related_category_ids).to be_empty | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       # [category_1, category_2] !== [category_2, category_1] | ||||||
|  |       it 'update reverse associations for related categories' do | ||||||
|  |         category.related_categories << related_category_2 | ||||||
|  |         category.save! | ||||||
|  |  | ||||||
|  |         expect(category.related_category_ids).to eq([related_category_2.id]) | ||||||
|  |  | ||||||
|  |         category_params = { | ||||||
|  |           category: { | ||||||
|  |             related_category_ids: [category.id] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         put "/api/v1/accounts/#{account.id}/portals/#{portal.slug}/categories/#{related_category_2.id}", | ||||||
|  |             params: category_params, | ||||||
|  |             headers: agent.create_new_auth_token | ||||||
|  |  | ||||||
|  |         expect(response).to have_http_status(:success) | ||||||
|  |  | ||||||
|  |         expect(category.reload.related_category_ids).to eq([related_category_2.id]) | ||||||
|  |         expect(related_category_2.reload.related_category_ids).to eq([category.id]) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| @@ -125,7 +237,9 @@ RSpec.describe 'Api::V1::Accounts::Categories', type: :request do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     context 'when it is an authenticated user' do |     context 'when it is an authenticated user' do | ||||||
|       it 'get all portals' do |       it 'get all categories in portal' do | ||||||
|  |         category_count = Category.all.count | ||||||
|  |  | ||||||
|         category2 = create(:category, name: 'test_category_2', portal: portal, locale: 'es', slug: 'category_slug_2') |         category2 = create(:category, name: 'test_category_2', portal: portal, locale: 'es', slug: 'category_slug_2') | ||||||
|         expect(category2.id).not_to be nil |         expect(category2.id).not_to be nil | ||||||
|  |  | ||||||
| @@ -133,7 +247,7 @@ RSpec.describe 'Api::V1::Accounts::Categories', type: :request do | |||||||
|             headers: agent.create_new_auth_token |             headers: agent.create_new_auth_token | ||||||
|         expect(response).to have_http_status(:success) |         expect(response).to have_http_status(:success) | ||||||
|         json_response = JSON.parse(response.body) |         json_response = JSON.parse(response.body) | ||||||
|         expect(json_response['payload'].count).to be 2 |         expect(json_response['payload'].count).to be(category_count + 1) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								spec/factories/related_categories.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								spec/factories/related_categories.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | FactoryBot.define do | ||||||
|  |   factory :related_category do | ||||||
|  |     category | ||||||
|  |     related_category | ||||||
|  |   end | ||||||
|  | end | ||||||
| @@ -9,8 +9,10 @@ RSpec.describe Category, type: :model do | |||||||
|   describe 'associations' do |   describe 'associations' do | ||||||
|     it { is_expected.to belong_to(:account) } |     it { is_expected.to belong_to(:account) } | ||||||
|     it { is_expected.to belong_to(:portal) } |     it { is_expected.to belong_to(:portal) } | ||||||
|     it { is_expected.to have_many(:folders) } |  | ||||||
|     it { is_expected.to have_many(:articles) } |     it { is_expected.to have_many(:articles) } | ||||||
|  |     it { is_expected.to have_many(:sub_categories) } | ||||||
|  |     it { is_expected.to have_many(:linked_categories) } | ||||||
|  |     it { is_expected.to have_many(:related_categories) } | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   describe 'search' do |   describe 'search' do | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								spec/models/related_category_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								spec/models/related_category_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | require 'rails_helper' | ||||||
|  |  | ||||||
|  | RSpec.describe RelatedCategory, type: :model do | ||||||
|  |   describe 'associations' do | ||||||
|  |     it { is_expected.to belong_to(:category) } | ||||||
|  |     it { is_expected.to belong_to(:related_category) } | ||||||
|  |   end | ||||||
|  | end | ||||||
		Reference in New Issue
	
	Block a user
	 Tejaswini Chile
					Tejaswini Chile