Wicked_PDF does not download when I switch to using form_with instead of form_tag - pdf

I noticed a bug with my view where my form could not be submitted after the initial submission to generate a PDF, and during research saw that form_with was the recommended way to build forms going forward with rails. I updated my form, and everything seems to be working the way it's supposed to, but now the PDF doesn't download as before and just seems to render the string in a response without generating the file. Using Wicked-PDF and Rails 5.2.1. Sorry if I'm missing something super obvious!
Using form_tag (pdf downloads as expected):
form in view:
<%= form_tag("download_pdf", format: :pdf, method: "get") do %>
<div class="input-group mb-3">
<%= collection_select(:location, :id, Location.all, :id, :name, {:include_blank => 'Filter by location'}, {:id => 'qr_code_loc_select', :selected_value => '', :name => 'location', :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= collection_select(:name, :id, DeviceType.all, :id, :name, {:include_blank => 'Filter by device type'}, {:id => 'qr_device_type_select', :selected_value => '', :name => "device_type", :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<input type="number" name="width" class="form-control label_size_input" id="label_width" step="0.001" placeholder="Label Width" autocomplete ='off' aria-describedby="basic-addon3">
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<div class="input-group mb-3">
<input type="number" name="height" class="form-control label_size_input" id="label_height" step="0.001" placeholder="Label Height" autocomplete ='off' aria-describedby="basic-addon3">
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<%= label_tag "qr_col", "Columns:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= select_tag "qr_col", options_for_select(["1","2", "3", "4", "5"], "3"), {:autocomplete => 'off'}%>
</div>
<%= label_tag "paper_size", "Paper Size:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= select_tag "paper_size", options_for_select(#paper_size, "A4"), {:autocomplete => 'off'}%>
</div>
<div class="btn-group mb-3" role="group" aria-label="pdf_export_button" id="pdf_export">
<%= hidden_field_tag :column_number %>
<%= hidden_field_tag :label_size %>
<%= hidden_field_tag :format, "pdf" %>
<%= submit_tag("Create PDF Document", {:class=> "btn btn-secondary"}) %>
<% end %>
</div>
in controller:
def download_pdf
#columns = params[:column_number].to_i
#height = params[:height]
#width = params[:width]
#paper_size = params[:paper_size]
#type = params[:device_type]
#location = params[:location]
if #type.blank?
if #location.blank?
#devices = Device.all
else
#devices = get_devices_by_location(#location)
end
else
if #location.blank?
#devices = Device.where('device_type_id=?', #type)
else
#devices = get_devices_by_type_and_location(#type, #location)
end
end
pdf_string = render_to_string(
template: "qr_codes/show.html.erb",
layout: "layouts/pdf_layout.pdf.erb",
viewport_size: '1280x1024',
page_size: #paper_size
)
respond_to do |format|
format.pdf do
pdf = WickedPdf.new.pdf_from_string(pdf_string)
send_data pdf, :filename => "report.pdf", :type => "application/pdf"
end
end
end
in console:
Started GET "/qr_codes/download_pdf?utf8=%E2%9C%93&location=&device_type=&width=&height=&qr_col=3&paper_size=A4&column_number=3&label_size=&format=pdf&commit=Create+PDF+Document" for 127.0.0.1 at 2018-11-14 20:03:51 -0500
Processing by QrCodesController#download_pdf as PDF
Parameters: {"utf8"=>"✓", "location"=>"", "device_type"=>"", "width"=>"", "height"=>"", "qr_col"=>"3", "paper_size"=>"A4", "column_number"=>"3", "label_size"=>"", "commit"=>"Create PDF Document"}
Rendering qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb
(0.4ms) SELECT COUNT(*) FROM "devices"
Device Load (0.6ms) SELECT "devices".* FROM "devices"
Rendered qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb (778.0ms)
"***************[\"/Users/joe/.rbenv/versions/2.5.0/bin/wkhtmltopdf\", \"-q\", \"file:////var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf20181114-912-1opkhpt.html\", \"/var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf_generated_file20181114-912-m57i12.pdf\"]***************"
Rendering text template
Rendered text template (0.1ms)
Sent data report.pdf (1.7ms)
Completed 200 OK in 3077ms (Views: 1.2ms | ActiveRecord: 1.0ms)
Using form_with (pdf does not generate as expected and only has an unformatted string in response):
form in view:
<%= form_with url: download_pdf_path(format: :pdf), method: "get" do |f| %>
<div class="input-group mb-3">
<%= f.collection_select(:id, Location.all, :id, :name, {:include_blank => 'Filter by location'}, {:id => 'qr_code_loc_select', :selected_value => '', :name => 'location', :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= f.collection_select(:id, DeviceType.all, :id, :name, {:include_blank => 'Filter by device type'}, {:id => 'qr_device_type_select', :selected_value => '', :name => "device_type", :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= f.number_field nil, {:name => "width", :id => "label_width", :class => "form-control label_size_input", :step => "0.001", :placeholder => "Label Width", :autocomplete => 'off'} %>
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<div class="input-group mb-3">
<%= f.number_field nil, {:name => "height", :id => "label_height", :class => "form-control label_size_input", :step => "0.001", :placeholder => "Label Height", :autocomplete => 'off'} %>
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<%= label_tag "qr_col", "Columns:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= f.select "column_number", options_for_select(["1","2", "3", "4", "5"], "3"), {:autocomplete => 'off'}, :id => "qr_col"%>
</div>
<%= label_tag "paper_size", "Paper Size:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= f.select "paper_size", options_for_select(#paper_size, "A4"), {:autocomplete => 'off'}%>
</div>
<div class="btn-group mb-3" role="group" aria-label="pdf_export_button" id="pdf_export">
<%= f.hidden_field :label_size %>
<%= f.submit("Create PDF Document", {:class=> "btn btn-secondary", :data => { turbolinks: false }}) %>
</div>
<% end %>
controller:
def download_pdf
#columns = params[:column_number].to_i
#height = params[:height]
#width = params[:width]
#paper_size = params[:paper_size]
#type = params[:device_type]
#location = params[:location]
if #type.blank?
if #location.blank?
#devices = Device.all
else
#devices = get_devices_by_location(#location)
end
else
if #location.blank?
#devices = Device.where('device_type_id=?', #type)
else
#devices = get_devices_by_type_and_location(#type, #location)
end
end
respond_to do |format|
format.pdf do
pdf = WickedPdf.new.pdf_from_string(
render_to_string(
template: 'qr_codes/show.html.erb',
layout: 'layouts/pdf_layout.pdf.erb',
page_size: #paper_size
),
)
send_data pdf, :filename =>'PDF Report-' + Time.now.strftime('%v %H:%M:%S').to_s, disposition: 'attachment', :type => "application/pdf"
end
end
end
in console:
Started GET "/qr_codes/download_pdf_path?utf8=%E2%9C%93&location=&device_type=&width=&height=&column_number=3&paper_size=A4&label_size=&format=pdf&commit=Create%20PDF%20Document" for 127.0.0.1 at 2018-11-14 20:01:04 -0500
Processing by QrCodesController#download_pdf as PDF
Parameters: {"utf8"=>"✓", "location"=>"", "device_type"=>"", "width"=>"", "height"=>"", "column_number"=>"3", "paper_size"=>"A4", "label_size"=>"", "commit"=>"Create PDF Document"}
Rendering qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb
(0.3ms) SELECT COUNT(*) FROM "devices"
Device Load (1.2ms) SELECT "devices".* FROM "devices"
Rendered qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb (453.5ms)
"***************[\"/Users/joe/.rbenv/versions/2.5.0/bin/wkhtmltopdf\", \"-q\", \"file:////var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf20181114-912-1ym4a9q.html\", \"/var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf_generated_file20181114-912-edkha0.pdf\"]***************"
Rendering text template
Rendered text template (0.1ms)
Sent data PDF Report-14-NOV-2018 20:01:07 (1.6ms)
Completed 200 OK in 2682ms (Views: 1.1ms | ActiveRecord: 1.5ms)

IT WAS SOMETHING DUMB--decided to turn my attention to the form_with documentation and found out that remote: true is set by default. If you set this to local: true, the issue is resolved. Hope that helps someone else!

Related

Layering navbar simple search with Ransack for further scoping

I have a search bar on my navigation header where users can search for the titles of articles. This will route them to the articles/browse.html.erb page where they can further scope the results down by categories and name of authors.
I have followed this tutorial to do the navbar search. I have attempted to use Ransack to allow further filtering on the browse page. However, i'm having diffculty combining the 2 search methods with the following issues:
1) The navbar search works fine and returns the correct results, but when i filter the results further again by category name, i get EDIT 0 results ALL the results.
2) When i do the initial search on the browse page itself with the article title, ransack works. However, Ransack doesn't seem to work when i further scope the results down by category/author name. (EDIT: ransack works for filter by category with the below edit in browse.html.erb, but not for author name)
browse.html.erb
<%= search_form_for #q, url: browse_articles_path, method: :get do |f| %>
<div class="form-group">
<div class = "row">
<div class="col-md-12 col-sm-12 col-xs-12">
<%= f.search_field :title_cont, placeholder: "Find Articles", class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<div class ="row">
<div class="col-md-6 col-sm-6 col-xs-6">
<%= f.select :categories_name_cont, options_from_collection_for_select(Category.all, //EDIT change "id" to// "name", "name", #q.categories_name_eq),
{ :prompt => "Any Category" },
{ class: "form-control" } %>
</div>
<div class="col-md-6 col-sm-6 col-xs-6">
<%= f.search_field :users_name_cont, class: "form-control", placeholder: "Author" %>
</div>
</div>
</div>
<div class="form-group">
<%= f.submit class: 'btn btn-primary btn-md' %>
</div>
<% end %>
<% if params[:search] %>
<%= render #articles %>
<% elsif params[:q] %>
<%= render #articles_morefilter %>
<% else %>
<%= render #articles %>
<% end %>
articles_controller.rb
def browse
if params[:search]
#articles = Article.search(params[:search])
#categories = Category.joins(:articles).where('articles.title LIKE ?', "%#{params[:search]}%").uniq
else
#articles = Article.published.order("cached_votes_up DESC")
#categories = Category.with_articles.order('name ASC').all
end
#q = Article.ransack(params[:q])
#articles_morefilter = #q.result.includes(:categories, :users)
end
EDIT model: article.rb
class Article < ApplicationRecord
belongs_to :user
has_many :article_categories
has_many :categories, through: :article_categories
def self.search(search)
where('title LIKE ?', "%#{search}%")
end
end
routes.rb
resources :articles do
collection do
get 'browse'
end
end
schema:
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "description"
t.bigint "user_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
end
_navigation.html.erb
<%= form_tag(browse_articles_path, :method => 'get', :id => "articles_search") do %>
<div class="form-group">
<%= text_field_tag :search, params[:search], placeholder: "Search", class: "form-control" %>
</div>
<button type="submit" class="btn btn-default">Search</button>
<% end %>
you should be able to simply search all the fields with ransack. (based on current browse.html.erb)
def browse
#q = Article.ransack(params[:q])
#articles = #q.result.includes(:categories, :users)
end

Simple form label class

I want to use simple-form and bootstrap to generate a horizontal form with 2 rows. The first row should have two inputs side by side - one for first name with one label and the second row should have an input for email. My problem is that that label for the first row is not getting the control-label class that is required for the horizontal form to render correctly. However, all the proper classes are being applied to the email field.
Below is my code:
= simple_form_for #order, :url => '/product/process_order', :html => {:class => 'form-horizontal'} do |f|
.form-inputs
.control-group
= f.label :first, "Full and last name"
.controls
= f.input_field :first, :class => "span2", :placeholder => 'First'
= f.input_field :last, :class => "span3" , :placeholder => 'Last'
= f.input :email, :placeholder => 'you#example.com'
Which generates:
<form accept-charset="UTF-8" action="/product/process_order" class="simple_form form-horizontal" id="new_order" method="post" novalidate="novalidate">
<div class="form-inputs">
<div class="control-group">
<label for="order_first">Full and last name</label>
<div class="controls">
<input class="string required span2" id="order_first" name="order[first]" placeholder="First" size="50" type="text">
<input class="string required span3" id="order_last" name="order[last]" placeholder="Last" size="50" type="text">
</div>
</div>
<div class="control-group email required">
<label class="email required control-label" for="order_email">
<abbr title="required">*</abbr> Email
</label>
<div class="controls"><input class="string email required" id="order_email" name="order[email]" placeholder="you#example.com" size="50" type="email"></div>
</div>
</div>
</form>
In your config/initializers/simple_form.rb file, find the label class line and set it to:
config.label_class = 'control-label'
Also, if you are using bootstrap, you can do a few other things in this file. This might also help you:
SimpleForm.setup do |config|
config.wrappers :my_wrapper, :class => 'control-group',
:hint_class => :field_with_hint, :error_class => :field_with_errors do |b|
b.use :html5
b.use :placeholder
b.optional :maxlength
b.optional :pattern
b.optional :min_max
b.optional :readonly
## Inputs
b.use :label
b.wrapper :my_wrapper, :tag => 'div', :class => 'controls' do |ba|
ba.use :input
ba.use :error, :wrap_with => { :tag => 'span', :class => 'label label-important' }
ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' }
end
end
config.default_wrapper = :my_wrapper
config.boolean_style = :nested
config.button_class = 'btn'
config.error_notification_tag = :div
config.error_notification_class = 'alert alert-error'
config.label_class = 'control-label'
config.form_class = 'form-horizontal'
config.generate_additional_classes_for = [:wrapper, :label, :input]
config.browser_validations = true
end
According to this you have to do something along the lines of this:
f.label :first, label: 'Full and last name'

Rails Bootstrap Navbar and refineryCMS

Does anyone have implemented the Rails Bootstrap Navbar in refineryCMS?
I'm having a hard time trying to figure out how to render the dropdown menu.
which should be the right way of accomplish this?
_menu.html.erb
<%
if (roots = local_assigns[:roots] || (collection ||= refinery_menu_pages).roots).present?
dom_id ||= 'menu'
css = [(css || 'menu'), 'clearfix'].flatten.join(' ')
hide_children = Refinery::Core.menu_hide_children if hide_children.nil?
-%>
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<nav id='<%= dom_id %>' class='<%= css %> nav'>
<ul class="nav">
<%= render :partial => '/refinery/menu_branch', :collection => roots,
:locals => {
:hide_children => hide_children,
:sibling_count => (roots.length - 1),
:menu_levels => local_assigns[:menu_levels],
:apply_css => true #if you don't care about class='first' class='last' or class='selected' set apply_css to false for speed.
} -%>
</ul>
</nav>
</div>
</div>
</div>
<% end -%>
_menu_branch.html.erb
<%
if !!local_assigns[:apply_css] and (classes = custom_menu_branch_css(local_assigns)).any?
css = "class='#{classes.join(' ')}'".html_safe
end
-%>
<li class="dropdown">
<% if menu_branch.children.present? && menu_branch.ancestors.length < 1 %>
<%= link_to(menu_branch.title, refinery.url_for(menu_branch.url), class: "dropdown-togle", data: { toggle: "dropdown" }) -%>
<% else %>
<%= link_to(menu_branch.title, refinery.url_for(menu_branch.url)) -%>
<% end %>
<% if ( (children = menu_branch.children unless hide_children).present? &&
(!local_assigns[:menu_levels] || menu_branch.ancestors.length < local_assigns[:menu_levels]) ) -%>
<ul class="dropdown-menu">
<%= render :partial => '/refinery/menu_branch', :collection => children,
:locals => {
:apply_css => local_assigns[:apply_css],
:hide_children => !!hide_children,
:menu_levels => local_assigns[:menu_levels]
} -%>
</ul>
</li>
<% end -%>
nav_bar snippet
<%= nav_bar :fixed => :top, :brand => "Fashionable Clicheizr 2.0", :responsive => true do %>
<%= menu_group do %>
<%= menu_item "Home", root_path %>
<%= menu_divider %>
<%= drop_down "Products" do %>
<%= menu_item "Things you can't afford", expensive_products_path %>
<%= menu_item "Things that won't suit you anyway", harem_pants_path %>
<%= menu_item "Things you're not even cool enough to buy anyway", hipster_products_path %>
<% if current_user.lives_in_hackney? %>
<%= menu_item "Bikes", fixed_wheel_bikes_path %>
<% end %>
<% end %>
<%= menu_item "About Us", about_us_path %>
<%= menu_item "Contact", contact_path %>
<% end %>
<%= menu_group :pull => :right do %>
<% if current_user %>
<%= menu_item "Log Out", log_out_path %>
<% else %>
<%= form_for #user, :url => session_path(:user), html => {:class=> "navbar-form pull-right"} do |f| -%>
<p><%= f.text_field :email %></p>
<p><%= f.password_field :password %></p>
<p><%= f.submit "Sign in" %></p>
<% end -%>
<% end %>
<% end %>
<% end %>
Faced for some hours with same issue.
Have solution with bit more pretty code (or just more close to refinery standarts), I believe, its better to override base Refinery menu_presenter
first of all take a look a bit simmilar quest http://refinerycms.com/guides/menu-presenter and this one too: http://refinerycms.com/guides/extending-controllers-with-decorators
So. Based on that article lets do this
app/decorators/models/refinery/page_decorator.rb:
Refinery::Page.class_eval do
def self.menu_pages
where :show_in_menu => true
end
end
app/helpers/application_helper.rb
module ApplicationHelper
def menu_header
menu_items = Refinery::Menu.new(Refinery::Page.menu_pages)
presenter = Refinery::Pages::MenuPresenter.new(menu_items, self)
presenter.first_css = nil
presenter.last_css = nil
presenter
end
end
in terminal run:
cd /path/to/app/
rake refinery:override presenter=refinery/pages/menu_presenter
It will generate app/presenters/refinery/pages/menu_presenter.rb change it to this:
require 'active_support/core_ext/string'
require 'active_support/configurable'
require 'action_view/helpers/tag_helper'
require 'action_view/helpers/url_helper'
module Refinery
module Pages
class MenuPresenter
include ActionView::Helpers::TagHelper
include ActionView::Helpers::UrlHelper
include ActiveSupport::Configurable
config_accessor :roots, :menu_tag, :list_tag, :list_item_tag, :css, :dom_id,
:max_depth, :selected_css, :first_css, :last_css, :list_first_css,
:list_dropdown_css, :list_item_dropdown_css,
:list_item__css, :link_dropdown_options, :carret
self.dom_id = :div
self.css = ["nav-collapse", "collapse", "navbar-responsive-collapse"]
self.menu_tag = :nav
self.list_tag = :ul
self.list_first_css = :nav
self.carret = '<b class="caret"></b>'
self.list_dropdown_css = "dropdown-menu"
self.link_dropdown_options = {class: "toggle-dropdown", data: {:toggle=>"dropdown"}}
self.list_item_tag = :li
self.list_item_dropdown_css = :dropdown
self.list_item__css = nil
self.selected_css = :active
self.first_css = :first
self.last_css = :last
def roots
config.roots.presence || collection.roots
end
attr_accessor :context, :collection
delegate :output_buffer, :output_buffer=, :to => :context
def initialize(collection, context)
#collection = collection
#context = context
end
def to_html
render_menu(roots) if roots.present?
end
private
def render_menu(items)
content_tag(menu_tag, :id => dom_id, :class => css) do
render_menu_items(items)
end
end
def render_menu_items(menu_items)
if menu_items.present?
content_tag(list_tag, :class => menu_items_css(menu_items)) do
menu_items.each_with_index.inject(ActiveSupport::SafeBuffer.new) do |buffer, (item, index)|
buffer << render_menu_item(item, index)
end
end
end
end
def render_menu_item(menu_item, index)
content_tag(list_item_tag, :class => menu_item_css(menu_item, index)) do
#cont = context.refinery.url_for(menu_item.url)
buffer = ActiveSupport::SafeBuffer.new
if check_for_dropdown_item(menu_item)
buffer << link_to((menu_item.title+carret).html_safe, "#", link_dropdown_options)
else
buffer << link_to(menu_item.title, context.refinery.url_for(menu_item.url))
end
buffer << render_menu_items(menu_item_children(menu_item))
buffer
end
end
def check_for_dropdown_item(menu_item)
(menu_item!=roots.first)&&(menu_item_children(menu_item).count > 0)
end
# Determines whether any item underneath the supplied item is the current item according to rails.
# Just calls selected_item? for each descendant of the supplied item
# unless it first quickly determines that there are no descendants.
def descendant_item_selected?(item)
item.has_children? && item.descendants.any?(&method(:selected_item?))
end
def selected_item_or_descendant_item_selected?(item)
selected_item?(item) || descendant_item_selected?(item)
end
# Determine whether the supplied item is the currently open item according to Refinery.
def selected_item?(item)
path = context.request.path
path = path.force_encoding('utf-8') if path.respond_to?(:force_encoding)
# Ensure we match the path without the locale, if present.
if %r{^/#{::I18n.locale}/} === path
path = path.split(%r{^/#{::I18n.locale}}).last.presence || "/"
end
# First try to match against a "menu match" value, if available.
return true if item.try(:menu_match).present? && path =~ Regexp.new(item.menu_match)
# Find the first url that is a string.
url = [item.url]
url << ['', item.url[:path]].compact.flatten.join('/') if item.url.respond_to?(:keys)
url = url.last.match(%r{^/#{::I18n.locale.to_s}(/.*)}) ? $1 : url.detect{|u| u.is_a?(String)}
# Now use all possible vectors to try to find a valid match
[path, URI.decode(path)].include?(url) || path == "/#{item.original_id}"
end
def menu_items_css(menu_items)
css = []
css << list_first_css if (roots == menu_items)
css << list_dropdown_css if (roots != menu_items)
css.reject(&:blank?).presence
end
def menu_item_css(menu_item, index)
css = []
css << list_item_dropdown_css if (check_for_dropdown_item(menu_item))
css << selected_css if selected_item_or_descendant_item_selected?(menu_item)
css << first_css if index == 0
css << last_css if index == menu_item.shown_siblings.length
css.reject(&:blank?).presence
end
def menu_item_children(menu_item)
within_max_depth?(menu_item) ? menu_item.children : []
end
def within_max_depth?(menu_item)
!max_depth || menu_item.depth < max_depth
end
end
end
end
almost done. add menu_header.to_html to your menu inside container of your menu like this:
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="#"><%=Refinery::Core::site_name %></a>
<%= menu_header.to_html %>
</div>
</div>
</div>
PS: RefineryCMS 2.1.0
Refinery 2.1.0 with Bootstrap 3
None of the solutions above worked for me. So I had to adapt from Valentine Konov's answer. Below you can find all of my files. You can always leave me a comment if you need any help. Here we go!
1) Check your RefineryCMS and Bootstrap versions
Gemfile
gem 'bootstrap-sass', '~> 3.1.1'
gem 'refinerycms', '~> 2.1.0'
2) Save a few lines of code
a. You actually have no need to create an app/decorators/models/refinery/page_decorator.rb file.
b. You can forget the menu_header method as well. This way, you'll have:
app/helpers/application_helper.rb
module ApplicationHelper
end
3) Now let's get to the real work
a. Override your default header with:
$ rake refinery:override view=refinery/_header.html
And change its code to:
app/views/refinery/_header.html.erb
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#"><%=Refinery::Core::site_name %></a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<%= Refinery::Pages::MenuPresenter.new(refinery_menu_pages, self).to_html %>
</div>
</div>
</nav>
b. Now go to terminal and run rake refinery:override presenter=refinery/pages/menu_presenter. It will generate a menu_presenter.rb file. Change it to this:
app/presenters/refinery/pages/menu_presenter.rb
require 'active_support/core_ext/string'
require 'active_support/configurable'
require 'action_view/helpers/tag_helper'
require 'action_view/helpers/url_helper'
module Refinery
module Pages
class MenuPresenter
include ActionView::Helpers::TagHelper
include ActionView::Helpers::UrlHelper
include ActiveSupport::Configurable
config_accessor :roots, :menu_tag, :list_tag, :list_item_tag, :css, :dom_id,
:max_depth, :selected_css, :first_css, :last_css, :list_first_css,
:list_dropdown_css, :list_item_dropdown_css,
:list_item__css, :link_dropdown_options, :carret
# self.dom_id = nil
# self.css = "pull-left"
self.menu_tag = :section
self.list_tag = :ul
self.list_first_css = ["nav", "navbar-nav", "navbar-right"]
self.carret = '<b class="caret"></b>'
self.list_dropdown_css = "dropdown-menu"
self.link_dropdown_options = {class: "dropdown-toggle", data: {:toggle=>"dropdown"}}
self.list_item_tag = :li
self.list_item_dropdown_css = :dropdown
self.list_item__css = nil
self.selected_css = :active
self.first_css = :first
self.last_css = :last
def roots
config.roots.presence || collection.roots
end
attr_accessor :context, :collection
delegate :output_buffer, :output_buffer=, :to => :context
def initialize(collection, context)
#collection = collection
#context = context
end
def to_html
render_menu(roots) if roots.present?
end
private
def render_menu(items)
content_tag(menu_tag, :id => dom_id, :class => css) do
render_menu_items(items)
end
end
def render_menu_items(menu_items)
if menu_items.present?
content_tag(list_tag, :class => menu_items_css(menu_items)) do
menu_items.each_with_index.inject(ActiveSupport::SafeBuffer.new) do |buffer, (item, index)|
buffer << render_menu_item(item, index)
end
end
end
end
def render_menu_item(menu_item, index)
content_tag(list_item_tag, :class => menu_item_css(menu_item, index)) do
#cont = context.refinery.url_for(menu_item.url)
buffer = ActiveSupport::SafeBuffer.new
if check_for_dropdown_item(menu_item)
buffer << link_to((menu_item.title+carret).html_safe, "#", link_dropdown_options)
else
buffer << link_to(menu_item.title, context.refinery.url_for(menu_item.url))
end
buffer << render_menu_items(menu_item_children(menu_item))
buffer
end
end
def check_for_dropdown_item(menu_item)
(menu_item!=roots.first)&&(menu_item_children(menu_item).count > 0)
end
# Determines whether any item underneath the supplied item is the current item according to rails.
# Just calls selected_item? for each descendant of the supplied item
# unless it first quickly determines that there are no descendants.
def descendant_item_selected?(item)
item.has_children? && item.descendants.any?(&method(:selected_item?))
end
def selected_item_or_descendant_item_selected?(item)
selected_item?(item) || descendant_item_selected?(item)
end
# Determine whether the supplied item is the currently open item according to Refinery.
def selected_item?(item)
path = context.request.path
path = path.force_encoding('utf-8') if path.respond_to?(:force_encoding)
# Ensure we match the path without the locale, if present.
if %r{^/#{::I18n.locale}/} === path
path = path.split(%r{^/#{::I18n.locale}}).last.presence || "/"
end
# First try to match against a "menu match" value, if available.
return true if item.try(:menu_match).present? && path =~ Regexp.new(item.menu_match)
# Find the first url that is a string.
url = [item.url]
url << ['', item.url[:path]].compact.flatten.join('/') if item.url.respond_to?(:keys)
url = url.last.match(%r{^/#{::I18n.locale.to_s}(/.*)}) ? $1 : url.detect{|u| u.is_a?(String)}
# Now use all possible vectors to try to find a valid match
[path, URI.decode(path)].include?(url) || path == "/#{item.original_id}"
end
def menu_items_css(menu_items)
css = []
css << list_first_css if (roots == menu_items)
css << list_dropdown_css if (roots != menu_items)
css.reject(&:blank?).presence
end
def menu_item_css(menu_item, index)
css = []
css << list_item_dropdown_css if (check_for_dropdown_item(menu_item))
css << selected_css if selected_item_or_descendant_item_selected?(menu_item)
css << first_css if index == 0
css << last_css if index == menu_item.shown_siblings.length
css.reject(&:blank?).presence
end
def menu_item_children(menu_item)
within_max_depth?(menu_item) ? menu_item.children : []
end
def within_max_depth?(menu_item)
!max_depth || menu_item.depth < max_depth
end
end
end
end
c. Restart your server and see the results. If you already have some pages created, your navbar should look similar to the one below:
Try this _menu_branch.html.erb
<% if ( (children = menu_branch.children unless hide_children).present? &&
(!local_assigns[:menu_levels] || menu_branch.ancestors.length < local_assigns[:menu_levels]) ) -%>
<%
if !!local_assigns[:apply_css] and (classes = menu_branch_css(local_assigns)).any?
css = "class='#{classes.join(' ')} dropdown'".html_safe
end
-%>
<li<%= ['', css].compact.join(' ').gsub(/\ *$/, '').html_safe %>>
<%= link_to("#{menu_branch.title} <b class='caret'></b>".html_safe, refinery.url_for(menu_branch.url), :class=>"dropdown-toggle", 'data-toggle'=>'dropdown') -%>
<ul class='dropdown-menu'>
<%= render :partial => '/refinery/menu_branch', :collection => children,
:locals => {
:apply_css => local_assigns[:apply_css],
:hide_children => !!hide_children,
:menu_levels => local_assigns[:menu_levels]
} -%>
</ul>
</li>
<% else -%>
<%
if !!local_assigns[:apply_css] and (classes = menu_branch_css(local_assigns)).any?
css = "class='#{classes.join(' ')}'".html_safe
end
-%>
<li<%= ['', css].compact.join(' ').gsub(/\ *$/, '').html_safe %>>
<%= link_to(menu_branch.title, refinery.url_for(menu_branch.url)) -%>
</li>
<% end -%>
_menu.html.erb
<%
# Collect the root items.
# ::Refinery::Menu is smart enough to remember all of the items in the original collection.
if (roots = local_assigns[:roots] || (collection ||= refinery_menu_pages).roots).present?
dom_id ||= 'menu'
css = [(css || 'menu clearfix')].flatten.join(' ')
hide_children = Refinery::Core.menu_hide_children if hide_children.nil?
-%>
<div id="main-menu" class="nav-collapse">
<nav id='<%= dom_id %>' class='<%= css %>'>
<ul id="main-menu-left" class="nav">
<%= render :partial => '/refinery/menu_branch', :collection => roots,
:locals => {
:hide_children => hide_children,
:sibling_count => (roots.length - 1),
:menu_levels => local_assigns[:menu_levels],
:apply_css => true #if you don't care about class='first' class='last' or class='selected' set apply_css to false for speed.
} -%>
</ul>
</nav>
</div>
<% end -%>
and _header.html.erb
<div class="container">
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<a data-target=".nav-collapse" data-toggle="collapse" class="btn btn-navbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<%= link_to Refinery::Core.site_name, refinery.root_path, :class => "brand" %>
<%= render(:partial => "/refinery/menu", :locals => {
:dom_id => 'menu',
:css => 'menu'
}) %>
</div>
</div>
</div>
</div>
The approach outlined by user1852788 worked for me. If you are using a menu with drop downs don't forget to load the bootstrap js in your application.js manifest file:
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require_tree .
And then call the dropdown function (I have a file called layout.js.coffee):
$('.dropdown-toggle').dropdown()
This Gist worked great for me for the latest of Refinery and Bootstrap https://gist.github.com/npflood/2d3f5fc44518ef231195
There is a gem that tries to solve this problem.
https://github.com/ghoppe/refinerycms-bootstrap
But I've been having problems with it personally.
I found much easier way to do this for refinerycms 2-0-stable
my solution is the following:
first _menu.html.erb update css variable with bootstrap classes and add necessary html for example I added div to wrap ul
<%
# Collect the root items.
# ::Refinery::Menu is smart enough to remember all of the items in the original collection.
if (roots = local_assigns[:roots] || (collection ||= refinery_menu_pages).roots).present?
dom_id ||= 'menu'
css = [(css || 'pull-right')].flatten.join(' ')
hide_children = Refinery::Core.menu_hide_children if hide_children.nil?
-%>
<nav id='<%= dom_id %>' class='<%= css %>'>
<div class="collapse navbar-collapse">
<ul class="nav nav-pills navbar-nav">
<%= render :partial => '/refinery/menu_branch', :collection => roots,
:locals => {
:hide_children => hide_children,
:sibling_count => (roots.length - 1),
:menu_levels => local_assigns[:menu_levels],
:apply_css => true #if you don't care about class='first' class='last' or class='selected' set apply_css to false for speed.
} -%>
</ul>
</div>
</nav>
<% end -%>
second _menu_branch.html.erb update class with bootstrap classes
<%
if !!local_assigns[:apply_css] and (classes = menu_branch_css(local_assigns)).any?
css = "class='#{classes.join(' ')}'".html_safe
end
-%>
<% if ( (children = menu_branch.children unless hide_children).present? &&
(!local_assigns[:menu_levels] || menu_branch.ancestors.length < local_assigns[:menu_levels]) ) -%>
<li class="dropdown">
<%= menu_branch.title %><b class="caret"></b>
<ul class='dropdown-menu'>
<%= render :partial => '/refinery/menu_branch', :collection => children,
:locals => {
:apply_css => local_assigns[:apply_css],
:hide_children => !!hide_children,
:menu_levels => local_assigns[:menu_levels]
} -%>
</ul>
<% else -%>
<li<%= ['', css].compact.join(' ').gsub(/\ *$/, '').html_safe %>>
<%= link_to(menu_branch.title, refinery.url_for(menu_branch.url)) -%>
<% end -%>
</li>
now your menu should display fine. To enable Active you just need to update /config/initializers/refinery/core.rb file by changing the following code:
change selected, to active
# CSS class selectors for menu helper
config.menu_css = {:selected=>"active", :first=>"first", :last=>"last"}

Pass Contest Id into URL for search in Index

I have two models, contest and submission. submission belongs_to contest and contest has_many submissions.
In the index action for submissions I have a search:
def index
contest_id = params[:contest_id]
#contest = Contest.find(contest_id)
if params[:search].blank?
#submissions = Submission.paginate(:per_page => 10, :page => params[:page])
else
#submissions = Submission.search(params[:search]).paginate(:per_page => 10, :page => params[:page])
end
#search = params[:search]
end
I think the right way to pass it in is through the search form in the submissions>index view:
<div class ="span12 row">
<%= form_tag submissions_path, :method => 'get', :class => "form-search pull-right" do %>
<%= text_field_tag :search, params[:search], :class => 'input-xlarge', :placeholder => 'Search by member, title or description' %>
<%= submit_tag "Search", :title => nil, :class => 'btn btn-primary' %>
<% end %>
</div>
And I have been able to come close using this:
<%= hidden_field :contest_id, #contest.id %>
In the form, but it's returning this in the url:
http://localhost:3000/submissions?utf8=%E2%9C%93&search=test&contest_id%5B%5D=&commit=Search
And an error:
Couldn't find Contest with id=
I've also tried this:
<%= hidden_field(:contest_id, :value => #contest.id ) %>
But it's returning similar url and error.
Right now, I'm stuck. If you have any idea, please let me know.
[edit - added html]
Before search:
<div class ="span12 row">
<form accept-charset="UTF-8" action="/submissions" class="form-search pull-right" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
<input class="input-xlarge" id="search" name="search" placeholder="Search by member, title or description" type="text" />
<input id="contest_id_5" name="contest_id[5]" type="hidden" />
<input class="btn btn-primary" name="commit" type="submit" value="Search" />
</form>
</div>
Here's what works from other links going to submissions:
From the submission show page:
<%= link_to 'Browse All Submissions', submissions_path(:contest_id => #contest.id), :class => 'btn btn-mini pull-right' %>`
and from the contest show page:
<%= link_to 'Browse All Submissions', submissions_path(:contest_id => #contest.id), :class => 'btn btn-mini pull-right' %>
Both of these pass the url "contest_id=5" which is what the controller needs to find a contest. The issue I'm having with search is finding the right syntax to get contest_id=5 to appear without the mumbo jumbo mucking it up.
This turned out to be an easy solution. Insert a hidden_field_tag in the search form:
<%= hidden_field_tag 'contest_id', #contest.id %>
This will pass the correct value into params:
http://localhost:3000/submissions?utf8=%E2%9C%93&search=new&contest_id=5&commit=Search

My form doesn submit with Jquery Validate + Rails Form

I have a form that submits correctly without jquery validate, but does not with jquery validate. Using jquery validate, it correctly shows when the field has less than 6 characters, and the error goes away when it is 6+. However, clicking on the button does nothing. The validate script is:
<% content_for :head do %>
<script type="text/javascript">
$(document).ready(function () {
alert("document ready");
$("#new_hotel").validate({
debug: true,
rules: {
"hotel[name]": {required: true, minlength: 6},
}
});
});
My form is this:
<div class="modal-body">
<%= form_for #hotel do |f| %>
<%= f.label :name %>
<%= f.text_field :name%>
<div class="modal-footer">
<a class="btn" data-dismiss="modal" aria-hidden="true">Cancel</a>
<%= f.submit 'Create Hotel' , :class => 'btn btn-primary', :type => 'submit' %>
</div>
<% end %>