mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-03 04:27:53 +00:00
feat: Add support to uncategorized articles (#6912)
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::BaseController
|
class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::BaseController
|
||||||
before_action :ensure_custom_domain_request, only: [:show, :index]
|
before_action :ensure_custom_domain_request, only: [:show, :index]
|
||||||
before_action :portal
|
before_action :portal
|
||||||
before_action :set_category, except: [:index]
|
before_action :set_category, except: [:index, :show]
|
||||||
before_action :set_article, only: [:show]
|
before_action :set_article, only: [:show]
|
||||||
layout 'portal'
|
layout 'portal'
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::B
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_article
|
def set_article
|
||||||
@article = @category.articles.find(permitted_params[:id])
|
@article = @portal.articles.find_by(slug: permitted_params[:article_slug])
|
||||||
@article.increment_view_count
|
@article.increment_view_count
|
||||||
@parsed_content = render_article_content(@article.content)
|
@parsed_content = render_article_content(@article.content)
|
||||||
end
|
end
|
||||||
@@ -39,7 +39,7 @@ class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::B
|
|||||||
end
|
end
|
||||||
|
|
||||||
def permitted_params
|
def permitted_params
|
||||||
params.permit(:slug, :category_slug, :locale, :id)
|
params.permit(:slug, :category_slug, :locale, :id, :article_slug)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_article_content(content)
|
def render_article_content(content)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class Public::Api::V1::Portals::BaseController < PublicController
|
|||||||
|
|
||||||
def set_locale(&)
|
def set_locale(&)
|
||||||
switch_locale_with_portal(&) if params[:locale].present?
|
switch_locale_with_portal(&) if params[:locale].present?
|
||||||
|
switch_locale_with_article(&) if params[:article_slug].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def switch_locale_with_portal(&)
|
def switch_locale_with_portal(&)
|
||||||
@@ -19,4 +20,16 @@ class Public::Api::V1::Portals::BaseController < PublicController
|
|||||||
|
|
||||||
I18n.with_locale(@locale, &)
|
I18n.with_locale(@locale, &)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def switch_locale_with_article(&)
|
||||||
|
article = Article.find_by(slug: params[:article_slug])
|
||||||
|
|
||||||
|
@locale = if article.category.present?
|
||||||
|
article.category.locale
|
||||||
|
else
|
||||||
|
'en'
|
||||||
|
end
|
||||||
|
|
||||||
|
I18n.with_locale(@locale, &)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export const buildPortalArticleURL = (
|
|||||||
portalSlug,
|
portalSlug,
|
||||||
categorySlug,
|
categorySlug,
|
||||||
locale,
|
locale,
|
||||||
articleId
|
articleSlug
|
||||||
) => {
|
) => {
|
||||||
const portalURL = buildPortalURL(portalSlug);
|
const portalURL = buildPortalURL(portalSlug);
|
||||||
return `${portalURL}/${locale}/${categorySlug}/${articleId}`;
|
return `${portalURL}/articles/${articleSlug}`;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ describe('PortalHelper', () => {
|
|||||||
hostURL: 'https://app.chatwoot.com',
|
hostURL: 'https://app.chatwoot.com',
|
||||||
helpCenterURL: 'https://help.chatwoot.com',
|
helpCenterURL: 'https://help.chatwoot.com',
|
||||||
};
|
};
|
||||||
expect(buildPortalArticleURL('handbook', 'culture', 'fr', 1)).toEqual(
|
expect(
|
||||||
'https://help.chatwoot.com/hc/handbook/fr/culture/1'
|
buildPortalArticleURL('handbook', 'culture', 'fr', 'article-slug')
|
||||||
);
|
).toEqual('https://help.chatwoot.com/hc/handbook/articles/article-slug');
|
||||||
window.chatwootConfig = {};
|
window.chatwootConfig = {};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export default {
|
|||||||
slug,
|
slug,
|
||||||
this.article.category.slug,
|
this.article.category.slug,
|
||||||
this.article.category.locale,
|
this.article.category.locale,
|
||||||
this.article.id
|
this.article.slug
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export default {
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
generateArticleUrl(article) {
|
generateArticleUrl(article) {
|
||||||
return `/hc/${article.portal.slug}/${article.category.locale}/${article.category.slug}/${article.id}`;
|
return `/hc/${article.portal.slug}/articles/${article.slug}`;
|
||||||
},
|
},
|
||||||
handleKeyboardEvent(e) {
|
handleKeyboardEvent(e) {
|
||||||
this.processKeyDownEvent(e);
|
this.processKeyDownEvent(e);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Article < ApplicationRecord
|
|||||||
inverse_of: :associated_articles,
|
inverse_of: :associated_articles,
|
||||||
optional: true
|
optional: true
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
belongs_to :category
|
belongs_to :category, optional: true
|
||||||
belongs_to :portal
|
belongs_to :portal
|
||||||
belongs_to :author, class_name: 'User'
|
belongs_to :author, class_name: 'User'
|
||||||
|
|
||||||
@@ -49,7 +49,6 @@ class Article < ApplicationRecord
|
|||||||
before_validation :ensure_article_slug
|
before_validation :ensure_article_slug
|
||||||
|
|
||||||
validates :account_id, presence: true
|
validates :account_id, presence: true
|
||||||
validates :category_id, presence: true
|
|
||||||
validates :author_id, presence: true
|
validates :author_id, presence: true
|
||||||
validates :title, presence: true
|
validates :title, presence: true
|
||||||
validates :content, presence: true
|
validates :content, presence: true
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
json.id article.id
|
json.id article.id
|
||||||
|
json.slug article.slug
|
||||||
json.title article.title
|
json.title article.title
|
||||||
json.content article.content
|
json.content article.content
|
||||||
json.description article.description
|
json.description article.description
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<section class="bg-white lg:container w-full py-6 px-4 flex flex-col h-full">
|
<section class="bg-white lg:container w-full py-6 px-4 flex flex-col h-full">
|
||||||
<div class="flex justify-between items-center w-full">
|
<div class="flex justify-between items-center w-full">
|
||||||
<h3 class="text-xl text-slate-900 font-semibold subpixel-antialiased leading-relaxed hover:underline">
|
<h3 class="text-xl text-slate-900 font-semibold subpixel-antialiased leading-relaxed hover:underline">
|
||||||
<a href="/hc/<%= portal.slug %>/<%= category.locale %>/<%= category.slug %>">
|
<a href="/hc/<%= portal.slug %>/<%= category.locale %>/categories/<%= category.slug %>">
|
||||||
<%= category.name %>
|
<%= category.name %>
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<% category.articles.published.order(position: :asc).take(5).each do |article| %>
|
<% category.articles.published.order(position: :asc).take(5).each do |article| %>
|
||||||
<a
|
<a
|
||||||
class="text-slate-800 hover:underline leading-8"
|
class="text-slate-800 hover:underline leading-8"
|
||||||
href="/hc/<%= portal.slug %>/<%= category.locale %>/<%= category.slug %>/<%= article.id %>"
|
href="/hc/<%= portal.slug %>/articles/<%= article.slug %>"
|
||||||
>
|
>
|
||||||
<div class="flex justify-between content-center my-1 -mx-1 p-1 rounded-lg hover:bg-slate-25">
|
<div class="flex justify-between content-center my-1 -mx-1 p-1 rounded-lg hover:bg-slate-25">
|
||||||
<%= article.title %>
|
<%= article.title %>
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
href="/hc/<%= portal.slug %>/<%= category.locale %>/<%= category.slug %>"
|
href="/hc/<%= portal.slug %>/<%= category.locale %>/categories/<%= category.slug %>"
|
||||||
class="flex flex-row items-center text-base font-medium text-woot-500 hover:underline mt-4"
|
class="flex flex-row items-center text-base font-medium text-woot-500 hover:underline mt-4"
|
||||||
style="color: <%= portal.color %>"
|
style="color: <%= portal.color %>"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<section class="bg-white lg:container w-full py-6 px-4 flex flex-col h-full">
|
||||||
|
<div class="flex justify-between items-center w-full">
|
||||||
|
<h3 class="text-xl text-slate-900 font-semibold subpixel-antialiased leading-relaxed hover:underline">
|
||||||
|
<%= category %>
|
||||||
|
</h3>
|
||||||
|
<span class="text-slate-500">
|
||||||
|
<%= render 'public/api/v1/portals/article_count', article_count: portal.articles.published.where(category_id: nil).size %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="py-4 w-full mt-2 flex-grow">
|
||||||
|
<% portal.articles.published.where(category_id: nil).order(position: :asc).take(5).each do |article| %>
|
||||||
|
<a
|
||||||
|
class="text-slate-800 hover:underline leading-8"
|
||||||
|
href="/hc/<%= portal.slug %>/articles/<%= article.slug %>"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between content-center my-1 -mx-1 p-1 rounded-lg hover:bg-slate-25">
|
||||||
|
<%= article.title %>
|
||||||
|
<span class="flex items-center">
|
||||||
|
<svg
|
||||||
|
class="w-4 h-4 fill-current text-slate-700"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M8.47 4.22a.75.75 0 0 0 0 1.06L15.19 12l-6.72 6.72a.75.75 0 1 0 1.06 1.06l7.25-7.25a.75.75 0 0 0 0-1.06L9.53 4.22a.75.75 0 0 0-1.06 0Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
<div class="bg-gradient-to-b from-white to-slate-50">
|
<div class="bg-gradient-to-b from-white to-slate-50">
|
||||||
<div class="max-w-5xl px-8 lg:px-4 pt-8 pb-16 mx-auto space-y-4 w-full">
|
<div class="max-w-5xl px-8 lg:px-4 pt-8 pb-16 mx-auto space-y-4 w-full">
|
||||||
|
<% if @article.category.present? %>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="text-slate-700 hover:underline leading-8 text-sm font-medium"
|
class="text-slate-700 hover:underline leading-8 text-sm font-medium"
|
||||||
@@ -23,11 +24,12 @@
|
|||||||
<span class="text-xs text-slate-600 px-1">/</span>
|
<span class="text-xs text-slate-600 px-1">/</span>
|
||||||
<a
|
<a
|
||||||
class="text-slate-700 hover:underline leading-8 text-sm font-medium"
|
class="text-slate-700 hover:underline leading-8 text-sm font-medium"
|
||||||
href="/hc/<%= @portal.slug %>/<%= @article.category.locale %>/<%= @article.category.slug %>"
|
href="/hc/<%= @portal.slug %>/<%= @article.category.locale %>/categories/<%= @article.category.slug %>"
|
||||||
>
|
>
|
||||||
<%= @article.category.name %>
|
<%= @article.category.name %>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
<h1 class="text-3xl font-bold md:tracking-normal leading-snug md:text-5xl text-slate-900">
|
<h1 class="text-3xl font-bold md:tracking-normal leading-snug md:text-5xl text-slate-900">
|
||||||
<%= @article.title %>
|
<%= @article.title %>
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<section class="bg-white lg:container w-full py-6 px-4 flex flex-col h-full">
|
<section class="bg-white lg:container w-full py-6 px-4 flex flex-col h-full">
|
||||||
<div class="flex justify-between items-center w-full">
|
<div class="flex justify-between items-center w-full">
|
||||||
<h3 class="text-xl text-slate-900 font-semibold subpixel-antialiased leading-relaxed hover:underline"">
|
<h3 class="text-xl text-slate-900 font-semibold subpixel-antialiased leading-relaxed hover:underline"">
|
||||||
<a href="/hc/<%= portal.slug %>/<%= category.locale %>/<%= category.slug %>">
|
<a href="/hc/<%= portal.slug %>/<%= category.locale %>/categories/<%= category.slug %>">
|
||||||
<%= category.name %>
|
<%= category.name %>
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
<div class="flex justify-between content-center h-8 my-1">
|
<div class="flex justify-between content-center h-8 my-1">
|
||||||
<a
|
<a
|
||||||
class="text-slate-800 hover:underline leading-8"
|
class="text-slate-800 hover:underline leading-8"
|
||||||
href="/hc/<%= portal.slug %>/<%= category.locale %>/<%= category.slug %>/<%= article.id %>"
|
href="/hc/<%= portal.slug %>/articles/<%= article.slug %>"
|
||||||
>
|
>
|
||||||
<%= article.title %>
|
<%= article.title %>
|
||||||
</a>
|
</a>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
href="/hc/<%= portal.slug %>/<%= category.locale %>/<%= category.slug %>"
|
href="/hc/<%= portal.slug %>/<%= category.locale %>/categories/<%= category.slug %>"
|
||||||
class="flex flex-row items-center text-base font-medium text-woot-600 hover:text-slate-900 hover:underline mt-4"
|
class="flex flex-row items-center text-base font-medium text-woot-600 hover:text-slate-900 hover:underline mt-4"
|
||||||
>
|
>
|
||||||
<%= I18n.t('public_portal.common.view_all_articles') %>
|
<%= I18n.t('public_portal.common.view_all_articles') %>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
<% @category.articles.published.order(:position).each do |article| %>
|
<% @category.articles.published.order(:position).each do |article| %>
|
||||||
<a
|
<a
|
||||||
class="text-slate-800 flex justify-between content-center mb-4 py-2"
|
class="text-slate-800 flex justify-between content-center mb-4 py-2"
|
||||||
href="/hc/<%= @portal.slug %>/<%= @category.locale %>/<%= @category.slug %>/<%= article.id %>"
|
href="/hc/<%= @portal.slug %>/articles/<%= article.slug %>"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium mb-2 hover:underline"><%= article.title %></p>
|
<p class="font-medium mb-2 hover:underline"><%= article.title %></p>
|
||||||
|
|||||||
@@ -5,4 +5,10 @@
|
|||||||
<%= render "public/api/v1/portals/category-block", category: category, portal: @portal %>
|
<%= render "public/api/v1/portals/category-block", category: category, portal: @portal %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-x-32 gap-y-0 lg:gap-y-12">
|
||||||
|
<% if @portal.articles.where(status: :published, category_id: nil).order(position: :asc) %>
|
||||||
|
<%= render "public/api/v1/portals/uncategorized-block", category: "Uncategorized", portal: @portal %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -338,9 +338,9 @@ Rails.application.routes.draw do
|
|||||||
get 'hc/:slug/:locale', to: 'public/api/v1/portals#show'
|
get 'hc/:slug/:locale', to: 'public/api/v1/portals#show'
|
||||||
get 'hc/:slug/:locale/articles', to: 'public/api/v1/portals/articles#index'
|
get 'hc/:slug/:locale/articles', to: 'public/api/v1/portals/articles#index'
|
||||||
get 'hc/:slug/:locale/categories', to: 'public/api/v1/portals/categories#index'
|
get 'hc/:slug/:locale/categories', to: 'public/api/v1/portals/categories#index'
|
||||||
get 'hc/:slug/:locale/:category_slug', to: 'public/api/v1/portals/categories#show'
|
get 'hc/:slug/:locale/categories/:category_slug', to: 'public/api/v1/portals/categories#show'
|
||||||
get 'hc/:slug/:locale/:category_slug/articles', to: 'public/api/v1/portals/articles#index'
|
get 'hc/:slug/:locale/categories/:category_slug/articles', to: 'public/api/v1/portals/articles#index'
|
||||||
get 'hc/:slug/:locale/:category_slug/:id', to: 'public/api/v1/portals/articles#show'
|
get 'hc/:slug/articles/:article_slug', to: 'public/api/v1/portals/articles#show'
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Used in mailer templates
|
# Used in mailer templates
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ RSpec.describe 'Public Articles API', type: :request do
|
|||||||
let!(:article) { create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id) }
|
let!(:article) { create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
ENV['HELPCENTER_URL'] = ENV.fetch('FRONTEND_URL', nil)
|
||||||
create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id)
|
create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id)
|
||||||
create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id, associated_article_id: article.id)
|
create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id, associated_article_id: article.id)
|
||||||
create(:article, category: category_2, portal: portal, account_id: account.id, author_id: agent.id, associated_article_id: article.id)
|
create(:article, category: category_2, portal: portal, account_id: account.id, author_id: agent.id, associated_article_id: article.id)
|
||||||
@@ -17,7 +18,7 @@ RSpec.describe 'Public Articles API', type: :request do
|
|||||||
|
|
||||||
describe 'GET /public/api/v1/portals/:slug/articles' do
|
describe 'GET /public/api/v1/portals/:slug/articles' do
|
||||||
it 'Fetch all articles in the portal' do
|
it 'Fetch all articles in the portal' do
|
||||||
get "/hc/#{portal.slug}/#{category.locale}/#{category.slug}/articles"
|
get "/hc/#{portal.slug}/#{category.locale}/categories/#{category.slug}/articles"
|
||||||
|
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
@@ -31,7 +32,7 @@ RSpec.describe 'Public Articles API', type: :request do
|
|||||||
content: 'this is some test and funny content')
|
content: 'this is some test and funny content')
|
||||||
expect(article2.id).not_to be_nil
|
expect(article2.id).not_to be_nil
|
||||||
|
|
||||||
get "/hc/#{portal.slug}/#{category.locale}/#{category.slug}/articles",
|
get "/hc/#{portal.slug}/#{category.locale}/categories/#{category.slug}/articles",
|
||||||
headers: agent.create_new_auth_token,
|
headers: agent.create_new_auth_token,
|
||||||
params: { query: 'funny' }
|
params: { query: 'funny' }
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
@@ -40,14 +41,14 @@ RSpec.describe 'Public Articles API', type: :request do
|
|||||||
|
|
||||||
describe 'GET /public/api/v1/portals/:slug/articles/:id' do
|
describe 'GET /public/api/v1/portals/:slug/articles/:id' do
|
||||||
it 'Fetch article with the id' do
|
it 'Fetch article with the id' do
|
||||||
get "/hc/#{portal.slug}/#{category.locale}/#{category.slug}/#{article.id}"
|
get "/hc/#{portal.slug}/articles/#{article.slug}"
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
expect(article.reload.views).to eq 1
|
expect(article.reload.views).to eq 1
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns the article with the id with a different locale' do
|
it 'returns the article with the id with a different locale' do
|
||||||
article_in_locale = create(:article, category: category_2, portal: portal, account_id: account.id, author_id: agent.id)
|
article_in_locale = create(:article, category: category_2, portal: portal, account_id: account.id, author_id: agent.id)
|
||||||
get "/hc/#{portal.slug}/#{category_2.locale}/#{category_2.slug}/#{article_in_locale.id}"
|
get "/hc/#{portal.slug}/articles/#{article_in_locale.slug}"
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ RSpec.describe 'Public Categories API', type: :request do
|
|||||||
|
|
||||||
describe 'GET /public/api/v1/portals/:portal_slug/categories' do
|
describe 'GET /public/api/v1/portals/:portal_slug/categories' do
|
||||||
it 'Fetch all categories in the portal' do
|
it 'Fetch all categories in the portal' do
|
||||||
get "/hc/#{portal.slug}/categories"
|
category = portal.categories.first
|
||||||
|
|
||||||
|
get "/hc/#{portal.slug}/#{category.locale}/categories"
|
||||||
|
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
@@ -20,9 +22,9 @@ RSpec.describe 'Public Categories API', type: :request do
|
|||||||
|
|
||||||
describe 'GET /public/api/v1/portals/:portal_slug/categories/:slug' do
|
describe 'GET /public/api/v1/portals/:portal_slug/categories/:slug' do
|
||||||
it 'Fetch category with the slug' do
|
it 'Fetch category with the slug' do
|
||||||
category_locale = 'en'
|
category = portal.categories.first
|
||||||
|
|
||||||
get "/hc/#{portal.slug}/#{category_locale}/categories"
|
get "/hc/#{portal.slug}/#{category.locale}/categories/#{category.slug}"
|
||||||
|
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ require 'rails_helper'
|
|||||||
RSpec.describe Article, type: :model do
|
RSpec.describe Article, type: :model do
|
||||||
context 'with validations' do
|
context 'with validations' do
|
||||||
it { is_expected.to validate_presence_of(:account_id) }
|
it { is_expected.to validate_presence_of(:account_id) }
|
||||||
it { is_expected.to validate_presence_of(:category_id) }
|
|
||||||
it { is_expected.to validate_presence_of(:author_id) }
|
it { is_expected.to validate_presence_of(:author_id) }
|
||||||
it { is_expected.to validate_presence_of(:title) }
|
it { is_expected.to validate_presence_of(:title) }
|
||||||
it { is_expected.to validate_presence_of(:content) }
|
it { is_expected.to validate_presence_of(:content) }
|
||||||
@@ -11,7 +10,6 @@ RSpec.describe Article, 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(:category) }
|
|
||||||
it { is_expected.to belong_to(:author) }
|
it { is_expected.to belong_to(:author) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user