kuhsaft 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +23 -0
- data/app/controllers/kuhsaft/pages_controller.rb +7 -0
- data/app/helpers/kuhsaft/cms/admin_helper.rb +12 -0
- data/app/helpers/pages_helper.rb +10 -0
- data/app/models/kuhsaft/brick.rb +7 -0
- data/app/models/kuhsaft/page.rb +49 -19
- data/app/models/kuhsaft/page_type.rb +2 -2
- data/app/models/kuhsaft/text_brick.rb +11 -1
- data/app/views/kuhsaft/cms/admin/_content_language_switch.html.haml +1 -1
- data/app/views/kuhsaft/pages/index.html.haml +7 -0
- data/app/views/kuhsaft/search/_form.html.haml +2 -0
- data/app/views/kuhsaft/search/_results.html.haml +8 -0
- data/app/views/kuhsaft/search/_results_entry.html.haml +13 -0
- data/config/locales/views/kuhsaft/search/de.yml +12 -0
- data/config/locales/views/kuhsaft/search/en.yml +12 -0
- data/config/routes.rb +4 -2
- data/db/migrate/12_regenerate_fulltext.rb +12 -0
- data/lib/kuhsaft.rb +1 -0
- data/lib/kuhsaft/brick_list.rb +4 -1
- data/lib/kuhsaft/searchable.rb +72 -0
- data/lib/kuhsaft/version.rb +1 -1
- data/spec/controllers/kuhsaft/pages_controller_spec.rb +44 -2
- data/spec/dummy/app/controllers/application_controller.rb +1 -0
- data/spec/features/cms_pages_spec.rb +19 -4
- data/spec/features/search_spec.rb +80 -0
- data/spec/helpers/kuhsaft/pages_helper_spec.rb +21 -0
- data/spec/lib/searchable_spec.rb +30 -0
- data/spec/models/brick_spec.rb +24 -0
- data/spec/models/page_spec.rb +72 -12
- data/spec/models/text_brick_spec.rb +11 -1
- data/spec/support/default_url_options.rb +36 -0
- metadata +52 -4
data/README.md
CHANGED
@@ -226,6 +226,29 @@ Simply override the default partial for the main navigation in your app with you
|
|
226
226
|
* Implement the `fulltext` method on your brick, return anything you want to be searchable.
|
227
227
|
* Customize the edit form behaviour of your brick by overriding methods like `to_style_class?`. See the `Brick` and `BrickList` files for more methods.
|
228
228
|
|
229
|
+
## Integrating search
|
230
|
+
|
231
|
+
Kuhsaft supports fulltext search when using PostgreSQL with a simple
|
232
|
+
LIKE fallback for any other ActiveRecord DB.
|
233
|
+
|
234
|
+
Add a call to the `search_page_form` helper in your views. This renders
|
235
|
+
the default search form. The query will be executed by kuhsaft.
|
236
|
+
|
237
|
+
# e.g. _footer.html.haml
|
238
|
+
= search_page_form
|
239
|
+
|
240
|
+
To customize the search and result views you can add your own partials
|
241
|
+
to your rails app. The following partials are overridable.
|
242
|
+
|
243
|
+
app/views/kuhsaft/search
|
244
|
+
├── _form.html.haml # Search form
|
245
|
+
├── _results.html.haml # Results list (@pages)
|
246
|
+
└── _results_entry.html.haml # Single result entry (@page)
|
247
|
+
|
248
|
+
When using PostgreSQL, an additional attribute `excerpt` will be
|
249
|
+
available on the page model. It includes a highlighted excerpt of the
|
250
|
+
matching `fulltext` column.
|
251
|
+
|
229
252
|
# LICENSE
|
230
253
|
|
231
254
|
See the file LICENSE.
|
@@ -2,6 +2,13 @@ module Kuhsaft
|
|
2
2
|
class PagesController < ::ApplicationController
|
3
3
|
respond_to :html
|
4
4
|
|
5
|
+
def index
|
6
|
+
@search = params[:search]
|
7
|
+
if @search.present?
|
8
|
+
@pages = Kuhsaft::Page.unscoped.published.content_page.search(@search)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
5
12
|
def show
|
6
13
|
url = locale.to_s
|
7
14
|
url += "/#{params[:url]}" if params[:url].present?
|
@@ -5,6 +5,18 @@ module Kuhsaft
|
|
5
5
|
def render_language_switch?
|
6
6
|
I18n.available_locales.size > 1
|
7
7
|
end
|
8
|
+
|
9
|
+
def link_to_content_locale(locale)
|
10
|
+
action = params[:action]
|
11
|
+
if params[:action] == 'create'
|
12
|
+
action = 'new'
|
13
|
+
elsif params[:action] == 'update'
|
14
|
+
action = 'edit'
|
15
|
+
end
|
16
|
+
|
17
|
+
link_to locale.to_s.upcase, url_for(
|
18
|
+
:action => action, :content_locale => locale)
|
19
|
+
end
|
8
20
|
end
|
9
21
|
end
|
10
22
|
end
|
data/app/helpers/pages_helper.rb
CHANGED
@@ -65,4 +65,14 @@ module PagesHelper
|
|
65
65
|
@content << content_tag(:p, t('kuhsaft.text_bricks.text_brick.read_less'), :class => 'read-less-text')
|
66
66
|
end
|
67
67
|
end
|
68
|
+
|
69
|
+
def search_page_form
|
70
|
+
form_tag kuhsaft.pages_path, :method => :get, :class => 'form-inline' do
|
71
|
+
if block_given?
|
72
|
+
yield
|
73
|
+
else
|
74
|
+
render 'kuhsaft/search/form'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
68
78
|
end
|
data/app/models/kuhsaft/brick.rb
CHANGED
@@ -29,6 +29,13 @@ module Kuhsaft
|
|
29
29
|
self.position ||= has_siblings? ? brick_list.bricks.maximum(:position).to_i + 1 : 1
|
30
30
|
end
|
31
31
|
|
32
|
+
after_save do
|
33
|
+
# TODO: replace callback with fulltext row on each
|
34
|
+
# searchable model
|
35
|
+
brick_list.update_fulltext
|
36
|
+
brick_list.save!
|
37
|
+
end
|
38
|
+
|
32
39
|
def to_edit_partial_path
|
33
40
|
path = self.to_partial_path.split '/'
|
34
41
|
path << 'edit'
|
data/app/models/kuhsaft/page.rb
CHANGED
@@ -1,26 +1,49 @@
|
|
1
1
|
class Kuhsaft::Page < ActiveRecord::Base
|
2
|
+
include Kuhsaft::Engine.routes.url_helpers
|
2
3
|
include Kuhsaft::Orderable
|
3
4
|
include Kuhsaft::Translatable
|
4
5
|
include Kuhsaft::BrickList
|
6
|
+
include Kuhsaft::Searchable
|
5
7
|
|
6
8
|
has_ancestry
|
7
9
|
acts_as_brick_list
|
8
10
|
|
9
|
-
translate :title,
|
10
|
-
|
11
|
+
translate :title,
|
12
|
+
:slug,
|
13
|
+
:keywords,
|
14
|
+
:description,
|
15
|
+
:body,
|
16
|
+
:redirect_url,
|
17
|
+
:url
|
18
|
+
|
19
|
+
attr_accessible :title,
|
20
|
+
:slug,
|
21
|
+
:redirect_url,
|
22
|
+
:url,
|
23
|
+
:page_type,
|
24
|
+
:parent_id,
|
25
|
+
:keywords,
|
26
|
+
:description,
|
27
|
+
:published
|
11
28
|
|
12
29
|
default_scope order('position ASC')
|
13
30
|
|
14
31
|
scope :published, where(:published => Kuhsaft::PublishState::PUBLISHED)
|
15
|
-
scope :search, lambda{ |term| published.where("`#{locale_attr(:fulltext)}` LIKE ?", "%#{term}%") }
|
16
|
-
scope :navigation, lambda{ |slug| where(locale_attr(:slug) => slug).where(locale_attr(:page_type) => Kuhsaft::PageType::NAVIGATION) }
|
17
32
|
|
18
|
-
|
33
|
+
# TODO: cleanup page_types (content pages => nil or PageType::CONTENT
|
34
|
+
scope :content_page, where(
|
35
|
+
["page_type is NULL or page_type = ?",
|
36
|
+
Kuhsaft::PageType::CONTENT])
|
37
|
+
|
38
|
+
scope :navigation, lambda{ |slug|
|
39
|
+
where(locale_attr(:slug) => slug).where(
|
40
|
+
locale_attr(:page_type) => Kuhsaft::PageType::NAVIGATION) }
|
41
|
+
|
42
|
+
before_validation :create_slug, :create_url
|
19
43
|
|
20
44
|
validates :title, :presence => true
|
21
45
|
validates :slug, :presence => true
|
22
46
|
validates :redirect_url, :presence => true, :if => :redirect?
|
23
|
-
#validates :url, :uniqueness => true, :unless => :navigation?
|
24
47
|
|
25
48
|
class << self
|
26
49
|
def flat_tree(pages = nil)
|
@@ -72,19 +95,30 @@ class Kuhsaft::Page < ActiveRecord::Base
|
|
72
95
|
if bricks.count == 0 && children.count > 0
|
73
96
|
children.first.link
|
74
97
|
else
|
75
|
-
|
98
|
+
url_with_locale
|
76
99
|
end
|
77
100
|
end
|
78
101
|
|
102
|
+
# TODO: needs naming and routing refactoring (url/locale/path/slug)
|
103
|
+
def path_segments
|
104
|
+
paths = parent.present? ? parent.path_segments : []
|
105
|
+
paths << slug unless navigation?
|
106
|
+
paths
|
107
|
+
end
|
108
|
+
|
109
|
+
def url_without_locale
|
110
|
+
path_segments.join('/')
|
111
|
+
end
|
112
|
+
|
113
|
+
def url_with_locale
|
114
|
+
opts = { :locale => I18n.locale }
|
115
|
+
url = url_without_locale
|
116
|
+
opts[:url] = url if url.present?
|
117
|
+
page_path(opts)
|
118
|
+
end
|
119
|
+
|
79
120
|
def create_url
|
80
|
-
|
81
|
-
if parent.present?
|
82
|
-
complete_slug << parent.url.to_s
|
83
|
-
else
|
84
|
-
complete_slug = "#{I18n.locale}"
|
85
|
-
end
|
86
|
-
complete_slug << "/#{self.slug}" unless navigation?
|
87
|
-
self.url = complete_slug
|
121
|
+
self.url = url_with_locale[1..-1]
|
88
122
|
end
|
89
123
|
|
90
124
|
def create_slug
|
@@ -92,10 +126,6 @@ class Kuhsaft::Page < ActiveRecord::Base
|
|
92
126
|
self.slug = title.downcase.parameterize if has_slug
|
93
127
|
end
|
94
128
|
|
95
|
-
def collect_fulltext
|
96
|
-
self.fulltext =[super, title.to_s, keywords.to_s, description.to_s].join(' ')
|
97
|
-
end
|
98
|
-
|
99
129
|
def nesting_name
|
100
130
|
num_dashes = parent_pages.size
|
101
131
|
num_dashes = 0 if num_dashes < 0
|
@@ -1,5 +1,10 @@
|
|
1
|
+
require 'htmlentities'
|
2
|
+
|
1
3
|
module Kuhsaft
|
2
4
|
class TextBrick < Brick
|
5
|
+
include ActionView::Helpers::SanitizeHelper
|
6
|
+
HTML_ENTITIES = HTMLEntities.new
|
7
|
+
|
3
8
|
attr_accessible :text, :read_more_text
|
4
9
|
|
5
10
|
def user_can_add_childs?
|
@@ -7,7 +12,12 @@ module Kuhsaft
|
|
7
12
|
end
|
8
13
|
|
9
14
|
def collect_fulltext
|
10
|
-
|
15
|
+
HTML_ENTITIES.decode(
|
16
|
+
strip_tags([
|
17
|
+
text,
|
18
|
+
read_more_text
|
19
|
+
].compact.join(' ')).squish
|
20
|
+
)
|
11
21
|
end
|
12
22
|
end
|
13
23
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
.link
|
2
|
+
= link_to page.link do
|
3
|
+
%h4= page.title
|
4
|
+
%h5= kuhsaft.page_url(:url => page.url_without_locale)
|
5
|
+
.summary
|
6
|
+
-if page.excerpt.present?
|
7
|
+
.excerpt!= page.excerpt
|
8
|
+
-elsif page.fulltext.present?
|
9
|
+
.fulltext!= excerpt(highlight(page.fulltext, @search), @search)
|
10
|
+
|
11
|
+
-if page.keywords.present?
|
12
|
+
.keywords
|
13
|
+
= page.keywords
|
data/config/routes.rb
CHANGED
@@ -10,7 +10,9 @@ Kuhsaft::Engine.routes.draw do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
scope ":locale", :locale => /#{I18n.available_locales.join('|')}/ do
|
13
|
-
resources :pages,
|
14
|
-
|
13
|
+
resources :pages,
|
14
|
+
:only => [:index],
|
15
|
+
:defaults => { :locale => I18n.locale }
|
16
|
+
match '(*url)' => 'pages#show', :as => :page
|
15
17
|
end
|
16
18
|
end
|
data/lib/kuhsaft.rb
CHANGED
data/lib/kuhsaft/brick_list.rb
CHANGED
@@ -3,7 +3,10 @@ module Kuhsaft
|
|
3
3
|
|
4
4
|
def self.included(base)
|
5
5
|
def base.acts_as_brick_list
|
6
|
-
self.has_many :bricks,
|
6
|
+
self.has_many :bricks,
|
7
|
+
:class_name => 'Kuhsaft::Brick',
|
8
|
+
:dependent => :destroy,
|
9
|
+
:as => :brick_list
|
7
10
|
end
|
8
11
|
end
|
9
12
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'pg_search'
|
3
|
+
|
4
|
+
module Kuhsaft
|
5
|
+
module Searchable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
DICTIONARIES = {
|
9
|
+
:en => 'english',
|
10
|
+
:de => 'german',
|
11
|
+
}
|
12
|
+
|
13
|
+
def update_fulltext
|
14
|
+
self.fulltext = collect_fulltext
|
15
|
+
end
|
16
|
+
|
17
|
+
included do
|
18
|
+
unless included_modules.include?(BrickList)
|
19
|
+
raise 'Kuhsaft::Searchable needs Kuhsaft::BrickList to be included'
|
20
|
+
end
|
21
|
+
|
22
|
+
if included_modules.include?(Translatable)
|
23
|
+
translate :fulltext
|
24
|
+
else
|
25
|
+
attr_accessible :fulltext
|
26
|
+
end
|
27
|
+
|
28
|
+
before_validation :update_fulltext
|
29
|
+
|
30
|
+
if ActiveRecord::Base.connection.instance_values['config'][:adapter] == 'postgresql'
|
31
|
+
include ::PgSearch
|
32
|
+
cb = lambda do |query|
|
33
|
+
{
|
34
|
+
:against => {
|
35
|
+
locale_attr(:title) => 'A',
|
36
|
+
locale_attr(:keywords) => 'B',
|
37
|
+
locale_attr(:description) => 'C',
|
38
|
+
locale_attr(:fulltext) => 'C',
|
39
|
+
},
|
40
|
+
:query => query,
|
41
|
+
:using => { :tsearch => { :dictionary => DICTIONARIES[I18n.locale] || 'simple' }}
|
42
|
+
}
|
43
|
+
end
|
44
|
+
pg_search_scope :search_without_excerpt, cb
|
45
|
+
scope :search, lambda { |query|
|
46
|
+
ts_headline = sanitize_sql_array([
|
47
|
+
"ts_headline(%s, plainto_tsquery('%s')) AS excerpt",
|
48
|
+
locale_attr(:fulltext),
|
49
|
+
query
|
50
|
+
])
|
51
|
+
search_without_excerpt(query).select(ts_headline)
|
52
|
+
}
|
53
|
+
else
|
54
|
+
# TODO: Tests run in this branch because dummy app uses mysql. Change it!
|
55
|
+
# define empty fallback excerpt attribute
|
56
|
+
attr_reader :excerpt
|
57
|
+
scope :search, lambda { |query|
|
58
|
+
if query.is_a? Hash
|
59
|
+
where("#{query.first[0]} LIKE ?", "%#{query.first[1]}%")
|
60
|
+
else
|
61
|
+
stmt = ""
|
62
|
+
stmt += "#{locale_attr(:keywords)} LIKE ? OR "
|
63
|
+
stmt += "#{locale_attr(:title)} LIKE ? OR "
|
64
|
+
stmt += "#{locale_attr(:description)} LIKE ? OR "
|
65
|
+
stmt += "#{locale_attr(:fulltext)} LIKE ?"
|
66
|
+
where(stmt, *(["%#{query}%"] * 4))
|
67
|
+
end
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/kuhsaft/version.rb
CHANGED
@@ -3,6 +3,24 @@ require 'spec_helper'
|
|
3
3
|
describe Kuhsaft::PagesController do
|
4
4
|
subject { described_class }
|
5
5
|
|
6
|
+
describe '#index' do
|
7
|
+
before do
|
8
|
+
@pages = [
|
9
|
+
create(:page, :page_type => Kuhsaft::PageType::CONTENT, :published => true, :fulltext_de => 'foobar'),
|
10
|
+
create(:page, :page_type => Kuhsaft::PageType::CONTENT, :published => true, :fulltext_de => 'barfoo')
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with search parameter' do
|
15
|
+
it 'assigns the search results' do
|
16
|
+
I18n.with_locale :de do
|
17
|
+
get(:index, { :use_route => :kuhsaft, :search => 'foobar' })
|
18
|
+
end
|
19
|
+
assigns(:pages).should eq([@pages.first])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
6
24
|
describe '#show' do
|
7
25
|
describe 'redirect' do
|
8
26
|
around(:each) do |example|
|
@@ -14,7 +32,7 @@ describe Kuhsaft::PagesController do
|
|
14
32
|
context 'when page is not a redirect page' do
|
15
33
|
it 'responds with page' do
|
16
34
|
page = FactoryGirl.create(:page, :slug => 'dumdidum', :url => 'de/dumdidum')
|
17
|
-
get :show, { :url => page.slug, :use_route => :kuhsaft
|
35
|
+
get :show, { :url => page.slug, :use_route => :kuhsaft }
|
18
36
|
assigns(:page).should eq(page)
|
19
37
|
end
|
20
38
|
end
|
@@ -22,7 +40,7 @@ describe Kuhsaft::PagesController do
|
|
22
40
|
context 'when page is a redirect page' do
|
23
41
|
it 'redirects to the redirected url' do
|
24
42
|
page = FactoryGirl.create(:page, :page_type => 'redirect', :slug => 'dumdidum', :url => 'de/dumdidum', :redirect_url => 'de/redirect_page')
|
25
|
-
get :show, { :url => page.slug, :use_route => :kuhsaft
|
43
|
+
get :show, { :url => page.slug, :use_route => :kuhsaft }
|
26
44
|
expect(response).to redirect_to("/de/redirect_page")
|
27
45
|
end
|
28
46
|
end
|
@@ -52,5 +70,29 @@ describe Kuhsaft::PagesController do
|
|
52
70
|
end
|
53
71
|
end
|
54
72
|
end
|
73
|
+
|
74
|
+
describe 'page type' do
|
75
|
+
around(:each) do |example|
|
76
|
+
I18n.with_locale :de do
|
77
|
+
example.run
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when page is not a redirect page' do
|
82
|
+
it 'responds with page' do
|
83
|
+
page = FactoryGirl.create(:page, :slug => 'dumdidum', :url => 'de/dumdidum')
|
84
|
+
get :show, { :url => page.slug, :use_route => :kuhsaft }
|
85
|
+
assigns(:page).should eq(page)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when page is a redirect page' do
|
90
|
+
it 'redirects to the redirected url' do
|
91
|
+
page = FactoryGirl.create(:page, :page_type => 'redirect', :slug => 'dumdidum', :url => 'de/dumdidum', :redirect_url => 'de/redirect_page')
|
92
|
+
get :show, { :url => page.slug, :use_route => :kuhsaft }
|
93
|
+
expect(response).to redirect_to("/de/redirect_page")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
55
97
|
end
|
56
98
|
end
|
@@ -13,12 +13,27 @@ describe 'Cms/Pages' do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
describe '#create' do
|
16
|
-
|
17
|
-
|
16
|
+
context 'when page is valid' do
|
17
|
+
it 'creates a new page' do
|
18
|
+
expect { click_on 'Create Seite' }.to change(Kuhsaft::Page, :count).by(1)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'is not possible to change the value in url' do
|
22
|
+
page.find('#page_url')['disabled'].should be_true
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
|
-
|
21
|
-
|
26
|
+
context 'when page is invalid' do
|
27
|
+
it 'does not create a routing error by switching the locale' do
|
28
|
+
@page = FactoryGirl.create(:page, :title => 'DummyPage', :title_en => 'DummyEN', :slug => 'dummy_page')
|
29
|
+
visit kuhsaft.edit_cms_page_path(@page)
|
30
|
+
fill_in 'page_title', :with => ''
|
31
|
+
click_on 'Update Seite'
|
32
|
+
within '.nav-pills' do
|
33
|
+
click_on 'EN'
|
34
|
+
end
|
35
|
+
page.should have_content(@page.title_en)
|
36
|
+
end
|
22
37
|
end
|
23
38
|
end
|
24
39
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'pages#index' do
|
4
|
+
context 'with search parameter' do
|
5
|
+
let! :page1 do
|
6
|
+
p = create :page,
|
7
|
+
:page_type => Kuhsaft::PageType::CONTENT,
|
8
|
+
:published => true,
|
9
|
+
:title => 'Chromodorididae Ardeadoris'
|
10
|
+
p.bricks << Kuhsaft::TextBrick.new(:locale => I18n.locale, :text => "#{'foo bar' * 300} Chromodorididae #{'foo bar' * 300}")
|
11
|
+
p.save!
|
12
|
+
p
|
13
|
+
end
|
14
|
+
|
15
|
+
let! :page2 do
|
16
|
+
create :page,
|
17
|
+
:page_type => Kuhsaft::PageType::CONTENT,
|
18
|
+
:published => true,
|
19
|
+
:title => 'Chromodorididae Berlanguella'
|
20
|
+
end
|
21
|
+
|
22
|
+
let! :page3 do
|
23
|
+
create :page,
|
24
|
+
:page_type => Kuhsaft::PageType::CONTENT,
|
25
|
+
:published => true,
|
26
|
+
:title => 'Gastropoda'
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with fulltext' do
|
30
|
+
before do
|
31
|
+
visit kuhsaft.pages_path(:locale => :en, :search => 'Chromodorididae')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'highlights search term in preview' do
|
35
|
+
within("ul.search-results strong.highlight") do
|
36
|
+
page.should have_content('Chromodorididae')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'truncates the text' do
|
41
|
+
find('.summary .fulltext').text.length.should < 200
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with multiple matches' do
|
46
|
+
before do
|
47
|
+
visit kuhsaft.pages_path(:locale => :en, :search => 'Chromodorididae')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'renders match count' do
|
51
|
+
page.should have_content("2 results")
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'renders the search results list' do
|
55
|
+
within("ul.search-results.success") do
|
56
|
+
page.should have_content('Chromodorididae Ardeadoris')
|
57
|
+
page.should have_content('Chromodorididae Berlanguella')
|
58
|
+
page.should_not have_content('Gastropoda')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'renders links to the pages' do
|
63
|
+
within("ul.search-results.success") do
|
64
|
+
page.should have_link('Chromodorididae Ardeadoris', href: page1.link)
|
65
|
+
page.should have_link('Chromodorididae Berlanguella', href: page2.link)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'without matches' do
|
71
|
+
before do
|
72
|
+
visit kuhsaft.pages_path(:locale => :en, :search => 'foobar')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'renders match count' do
|
76
|
+
page.should have_content("No results")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PagesHelper do
|
4
|
+
describe '#search_page_form' do
|
5
|
+
|
6
|
+
context 'without block' do
|
7
|
+
it 'renders the default search form' do
|
8
|
+
form = search_page_form
|
9
|
+
form.should have_css('form.form-inline')
|
10
|
+
form.should have_css('input[type=text]')
|
11
|
+
form.should have_css('input[type=submit]')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with block' do
|
16
|
+
it 'calls the given block' do
|
17
|
+
expect { |b| search_page_form(&b) }.to yield_with_no_args
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kuhsaft::Searchable do
|
4
|
+
|
5
|
+
context 'with missing includes' do
|
6
|
+
it 'raises exteption when class does not include Kuhsaft::Bricklist' do
|
7
|
+
expect {
|
8
|
+
class Foo
|
9
|
+
include Kuhsaft::Searchable
|
10
|
+
end
|
11
|
+
}.to raise_error(/needs Kuhsaft::BrickList to be included/)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with Bricklist included' do
|
16
|
+
class SearchableDemo < ActiveRecord::Base
|
17
|
+
include Kuhsaft::BrickList
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'without postgresql' do
|
21
|
+
it 'initializes scope' do
|
22
|
+
ActiveRecord::Base.connection.instance_values.should_not == 'postgresql'
|
23
|
+
SearchableDemo.should_receive :scope
|
24
|
+
SearchableDemo.class_eval do
|
25
|
+
include Kuhsaft::Searchable
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/spec/models/brick_spec.rb
CHANGED
@@ -107,4 +107,28 @@ describe Kuhsaft::Brick do
|
|
107
107
|
brick.uploader?.should be_false
|
108
108
|
end
|
109
109
|
end
|
110
|
+
|
111
|
+
describe '#after_save' do
|
112
|
+
describe 'update_fulltext' do
|
113
|
+
let! :brick do
|
114
|
+
Kuhsaft::Brick.new.tap do |b|
|
115
|
+
b.type = Kuhsaft::BrickType.new
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
let! :brick_list do
|
120
|
+
p = create(:page)
|
121
|
+
p.bricks << brick
|
122
|
+
p.save
|
123
|
+
p
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'updates fulltext on bricklist after saving a single brick' do
|
127
|
+
brick.brick_list.should_receive(:update_fulltext)
|
128
|
+
brick.brick_list.should_receive(:save!)
|
129
|
+
brick.text = 'foobar'
|
130
|
+
brick.save
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
110
134
|
end
|
data/spec/models/page_spec.rb
CHANGED
@@ -21,6 +21,10 @@ describe Kuhsaft::Page do
|
|
21
21
|
it 'should only find published results' do
|
22
22
|
Kuhsaft::Page.search('English Title').should be_all { |p| p.published? == true }
|
23
23
|
end
|
24
|
+
|
25
|
+
it 'should find by using the old api' do
|
26
|
+
Kuhsaft::Page.search('English').should == Kuhsaft::Page.search('English')
|
27
|
+
end
|
24
28
|
end
|
25
29
|
|
26
30
|
describe '.position_of' do
|
@@ -72,6 +76,15 @@ describe Kuhsaft::Page do
|
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
79
|
+
describe '#content_page' do
|
80
|
+
it 'returns only content pages ("" or nil)' do
|
81
|
+
p1, p2, p3 = 3.times.map { create(:page) }
|
82
|
+
p2.update_attribute :page_type, Kuhsaft::PageType::REDIRECT
|
83
|
+
p3.update_attribute :page_type, nil
|
84
|
+
Kuhsaft::Page.content_page.should == [p1, p3]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
75
88
|
describe "#state_class" do
|
76
89
|
|
77
90
|
let(:page) { Kuhsaft::Page.new }
|
@@ -259,6 +272,13 @@ describe Kuhsaft::Page do
|
|
259
272
|
page.link.should eq('/en/news')
|
260
273
|
end
|
261
274
|
end
|
275
|
+
|
276
|
+
context 'when url part is empty' do
|
277
|
+
it 'strips the trailing slash' do
|
278
|
+
page = create(:page, :page_type => Kuhsaft::PageType::NAVIGATION)
|
279
|
+
page.link.should eq('/en')
|
280
|
+
end
|
281
|
+
end
|
262
282
|
end
|
263
283
|
|
264
284
|
describe '#navigation?' do
|
@@ -303,18 +323,6 @@ describe Kuhsaft::Page do
|
|
303
323
|
page.save
|
304
324
|
end
|
305
325
|
|
306
|
-
it 'contains the title' do
|
307
|
-
page.fulltext.should include('my title')
|
308
|
-
end
|
309
|
-
|
310
|
-
it 'contains the keywords' do
|
311
|
-
page.fulltext.should include('key words')
|
312
|
-
end
|
313
|
-
|
314
|
-
it 'contains the description' do
|
315
|
-
page.fulltext.should include('descrip tion')
|
316
|
-
end
|
317
|
-
|
318
326
|
it 'contains the page part content' do
|
319
327
|
page.fulltext.should include('oh la la')
|
320
328
|
end
|
@@ -333,4 +341,56 @@ describe Kuhsaft::Page do
|
|
333
341
|
page.url.should be_present
|
334
342
|
end
|
335
343
|
end
|
344
|
+
|
345
|
+
describe '#url_without_locale' do
|
346
|
+
let :page do
|
347
|
+
create(:page, :slug => 'page')
|
348
|
+
end
|
349
|
+
|
350
|
+
context 'without parent' do
|
351
|
+
it 'returns url without leading /' do
|
352
|
+
page.url_without_locale.should_not start_with '/'
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'returns a single slug' do
|
356
|
+
page.url_without_locale.should == 'page'
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
context 'when parent is navigation' do
|
361
|
+
let :parent do
|
362
|
+
create(:page, :page_type => Kuhsaft::PageType::NAVIGATION)
|
363
|
+
end
|
364
|
+
|
365
|
+
let :child do
|
366
|
+
create(:page, :slug => 'child', :parent => parent)
|
367
|
+
end
|
368
|
+
|
369
|
+
it 'returns url without leading /' do
|
370
|
+
child.url_without_locale.should_not start_with '/'
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'does not concatenate the parent slug' do
|
374
|
+
child.url_without_locale.should == 'child'
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
context 'when parent is normal page' do
|
379
|
+
let :parent do
|
380
|
+
create(:page, :slug => 'parent')
|
381
|
+
end
|
382
|
+
|
383
|
+
let :child do
|
384
|
+
create(:page, :slug => 'child', :parent => parent)
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'returns url without leading /' do
|
388
|
+
child.url_without_locale.should_not start_with '/'
|
389
|
+
end
|
390
|
+
|
391
|
+
it 'does not concatenate the parent slug' do
|
392
|
+
child.url_without_locale.should == 'parent/child'
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
336
396
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Kuhsaft::TextBrick do
|
4
|
-
|
5
4
|
let :text_brick do
|
6
5
|
Kuhsaft::TextBrick.new
|
7
6
|
end
|
@@ -17,4 +16,15 @@ describe Kuhsaft::TextBrick do
|
|
17
16
|
text_brick.user_can_add_childs?.should be_false
|
18
17
|
end
|
19
18
|
end
|
19
|
+
|
20
|
+
describe '#collect_fulltext' do
|
21
|
+
before do
|
22
|
+
text_brick.text = '<div><b>foo</b> <b>bar</b></div>'
|
23
|
+
text_brick.read_more_text = '<div><span>foo</span><span>bar</span></div>'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'sanitizes text and read_more_text' do
|
27
|
+
text_brick.collect_fulltext.should == 'foo bar foobar'
|
28
|
+
end
|
29
|
+
end
|
20
30
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ActionView::TestCase::TestController
|
2
|
+
def default_url_options(options={})
|
3
|
+
{ :locale => I18n.locale }.merge options
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
# The following snippet breaks url_for
|
8
|
+
# as described by franca
|
9
|
+
# https://github.com/screenconcept/shoestrap/issues/23
|
10
|
+
# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
11
|
+
#class ActionDispatch::Routing::RouteSet
|
12
|
+
#def default_url_options(options={})
|
13
|
+
#{ :locale => I18n.locale }
|
14
|
+
#end
|
15
|
+
#end
|
16
|
+
# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
17
|
+
|
18
|
+
# Fixes the missing default locale problem in controller specs
|
19
|
+
# See http://www.ruby-forum.com/topic/3448797#1041659
|
20
|
+
class ActionController::TestCase
|
21
|
+
module Behavior
|
22
|
+
def process_with_default_locale(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
|
23
|
+
parameters = { :locale => I18n.locale }.merge( parameters || {} )
|
24
|
+
process_without_default_locale(action, parameters, session, flash, http_method)
|
25
|
+
end
|
26
|
+
alias_method_chain :process, :default_locale
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module ActionDispatch::Assertions::RoutingAssertions
|
31
|
+
def assert_recognizes_with_default_locale(expected_options, path, extras = {}, message=nil)
|
32
|
+
expected_options = { :locale => I18n.locale.to_s }.merge(expected_options || {} )
|
33
|
+
assert_recognizes_without_default_locale(expected_options, path, extras, message)
|
34
|
+
end
|
35
|
+
alias_method_chain :assert_recognizes, :default_locale
|
36
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kuhsaft
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2013-05-
|
16
|
+
date: 2013-05-31 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: rspec
|
@@ -319,6 +319,38 @@ dependencies:
|
|
319
319
|
- - '='
|
320
320
|
- !ruby/object:Gem::Version
|
321
321
|
version: 4.0.2
|
322
|
+
- !ruby/object:Gem::Dependency
|
323
|
+
name: pg_search
|
324
|
+
requirement: !ruby/object:Gem::Requirement
|
325
|
+
none: false
|
326
|
+
requirements:
|
327
|
+
- - ! '>='
|
328
|
+
- !ruby/object:Gem::Version
|
329
|
+
version: '0'
|
330
|
+
type: :runtime
|
331
|
+
prerelease: false
|
332
|
+
version_requirements: !ruby/object:Gem::Requirement
|
333
|
+
none: false
|
334
|
+
requirements:
|
335
|
+
- - ! '>='
|
336
|
+
- !ruby/object:Gem::Version
|
337
|
+
version: '0'
|
338
|
+
- !ruby/object:Gem::Dependency
|
339
|
+
name: htmlentities
|
340
|
+
requirement: !ruby/object:Gem::Requirement
|
341
|
+
none: false
|
342
|
+
requirements:
|
343
|
+
- - ! '>='
|
344
|
+
- !ruby/object:Gem::Version
|
345
|
+
version: '0'
|
346
|
+
type: :runtime
|
347
|
+
prerelease: false
|
348
|
+
version_requirements: !ruby/object:Gem::Requirement
|
349
|
+
none: false
|
350
|
+
requirements:
|
351
|
+
- - ! '>='
|
352
|
+
- !ruby/object:Gem::Version
|
353
|
+
version: '0'
|
322
354
|
description: Kuhsaft is a Rails engine that offers a simple CMS.
|
323
355
|
email: developers@screenconcept.ch
|
324
356
|
executables: []
|
@@ -402,9 +434,13 @@ files:
|
|
402
434
|
- app/views/kuhsaft/image_bricks/image_brick/_edit.html.haml
|
403
435
|
- app/views/kuhsaft/link_bricks/_link_brick.html.haml
|
404
436
|
- app/views/kuhsaft/link_bricks/link_brick/_edit.html.haml
|
437
|
+
- app/views/kuhsaft/pages/index.html.haml
|
405
438
|
- app/views/kuhsaft/pages/show.html.haml
|
406
439
|
- app/views/kuhsaft/placeholder_bricks/_placeholder_brick.html.haml
|
407
440
|
- app/views/kuhsaft/placeholder_bricks/placeholder_brick/_edit.html.haml
|
441
|
+
- app/views/kuhsaft/search/_form.html.haml
|
442
|
+
- app/views/kuhsaft/search/_results.html.haml
|
443
|
+
- app/views/kuhsaft/search/_results_entry.html.haml
|
408
444
|
- app/views/kuhsaft/slider_bricks/_slider_brick.html.haml
|
409
445
|
- app/views/kuhsaft/slider_bricks/slider_brick/_edit.html.haml
|
410
446
|
- app/views/kuhsaft/text_bricks/_text_brick.html.haml
|
@@ -438,6 +474,8 @@ files:
|
|
438
474
|
- config/locales/views/kuhsaft/cms/bricks/de.yml
|
439
475
|
- config/locales/views/kuhsaft/cms/pages/de.yml
|
440
476
|
- config/locales/views/kuhsaft/cms/video_bricks/de.yml
|
477
|
+
- config/locales/views/kuhsaft/search/de.yml
|
478
|
+
- config/locales/views/kuhsaft/search/en.yml
|
441
479
|
- config/locales/views/kuhsaft/text_brick/de.yml
|
442
480
|
- config/locales/views/layouts/de.yml
|
443
481
|
- config/routes.rb
|
@@ -452,6 +490,7 @@ files:
|
|
452
490
|
- db/migrate/09_add_additional_fields_to_kuhsaft_bricks.rb
|
453
491
|
- db/migrate/10_add_redirect_url_to_kuhsaft_pages.rb
|
454
492
|
- db/migrate/11_update_url_and_redirect_url_value.rb
|
493
|
+
- db/migrate/12_regenerate_fulltext.rb
|
455
494
|
- db/seeds.rb
|
456
495
|
- lib/generators/kuhsaft/assets/install_generator.rb
|
457
496
|
- lib/generators/kuhsaft/translations/add_generator.rb
|
@@ -459,6 +498,7 @@ files:
|
|
459
498
|
- lib/kuhsaft/engine.rb
|
460
499
|
- lib/kuhsaft/orderable.rb
|
461
500
|
- lib/kuhsaft/partial_extractor.rb
|
501
|
+
- lib/kuhsaft/searchable.rb
|
462
502
|
- lib/kuhsaft/translatable.rb
|
463
503
|
- lib/kuhsaft/version.rb
|
464
504
|
- lib/kuhsaft.rb
|
@@ -505,10 +545,13 @@ files:
|
|
505
545
|
- spec/dummy/script/rails
|
506
546
|
- spec/factories.rb
|
507
547
|
- spec/features/cms_pages_spec.rb
|
548
|
+
- spec/features/search_spec.rb
|
508
549
|
- spec/helpers/kuhsaft/cms/admin_helper_spec.rb
|
550
|
+
- spec/helpers/kuhsaft/pages_helper_spec.rb
|
509
551
|
- spec/kuhsaft_spec.rb
|
510
552
|
- spec/lib/brick_list_spec.rb
|
511
553
|
- spec/lib/engine_spec.rb
|
554
|
+
- spec/lib/searchable_spec.rb
|
512
555
|
- spec/lib/translatable_spec.rb
|
513
556
|
- spec/models/accordion_brick_spec.rb
|
514
557
|
- spec/models/accordion_item_brick_spec.rb
|
@@ -529,6 +572,7 @@ files:
|
|
529
572
|
- spec/models/two_column_brick_spec.rb
|
530
573
|
- spec/models/video_brick_spec.rb
|
531
574
|
- spec/spec_helper.rb
|
575
|
+
- spec/support/default_url_options.rb
|
532
576
|
- spec/support/kuhsaft_spec_helper.rb
|
533
577
|
homepage: http://github.com/screenconcept/kuhsaft
|
534
578
|
licenses: []
|
@@ -544,7 +588,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
544
588
|
version: '0'
|
545
589
|
segments:
|
546
590
|
- 0
|
547
|
-
hash:
|
591
|
+
hash: 2803199904668343026
|
548
592
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
549
593
|
none: false
|
550
594
|
requirements:
|
@@ -553,7 +597,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
553
597
|
version: '0'
|
554
598
|
segments:
|
555
599
|
- 0
|
556
|
-
hash:
|
600
|
+
hash: 2803199904668343026
|
557
601
|
requirements: []
|
558
602
|
rubyforge_project: kuhsaft
|
559
603
|
rubygems_version: 1.8.24
|
@@ -597,10 +641,13 @@ test_files:
|
|
597
641
|
- spec/dummy/script/rails
|
598
642
|
- spec/factories.rb
|
599
643
|
- spec/features/cms_pages_spec.rb
|
644
|
+
- spec/features/search_spec.rb
|
600
645
|
- spec/helpers/kuhsaft/cms/admin_helper_spec.rb
|
646
|
+
- spec/helpers/kuhsaft/pages_helper_spec.rb
|
601
647
|
- spec/kuhsaft_spec.rb
|
602
648
|
- spec/lib/brick_list_spec.rb
|
603
649
|
- spec/lib/engine_spec.rb
|
650
|
+
- spec/lib/searchable_spec.rb
|
604
651
|
- spec/lib/translatable_spec.rb
|
605
652
|
- spec/models/accordion_brick_spec.rb
|
606
653
|
- spec/models/accordion_item_brick_spec.rb
|
@@ -621,4 +668,5 @@ test_files:
|
|
621
668
|
- spec/models/two_column_brick_spec.rb
|
622
669
|
- spec/models/video_brick_spec.rb
|
623
670
|
- spec/spec_helper.rb
|
671
|
+
- spec/support/default_url_options.rb
|
624
672
|
- spec/support/kuhsaft_spec_helper.rb
|