Rails Bootstrap Navbar and refineryCMS - ruby-on-rails-3
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"}
Related
Wicked_PDF does not download when I switch to using form_with instead of form_tag
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!
Comments route in Rails 5.1
I am trying to create Comments on User created Articles in Rails 5.1. After a Comment is submitted, the redirect should be to the '/articles/:id' but is instead redirecting to '/articles/:id/comments'. I'm using nested routing in routes.rb: devise_for :users root to: "articles#index" resources :articles do resources :comments end My CommentsController.rb: class CommentsController < ApplicationController before_action :set_article def create unless current_user flash[:alert] = "Please sign in or sign up first" redirect_to new_user_session_path else #comment = #article.comments.build(comment_params) #comment.user = current_user if #comment.save flash[:notice] = "Comment has been created" else flash.now[:alert] = "Comment not created correctly" end redirect_to article_path(#article) end end private def comment_params params.require(:comment).permit(:body) end def set_article #article = Article.find(params[:id]) end end The form for Comments in articles/show.html.erb: <!--Start of comments--> <div class="col-md-12"> <%= form_for [#article, #comment], :html => {class: "form-horizontal", role: "form"} do |f| %> <% if #comment.errors.any? %> <div class="panel panel-danger col-md-offset-1"> <div class="panel-heading"> <h2 class="panel-title"> <%= pluralize(#comment.error.count, "error") %> prohibited this comment from being saved: </h2> <div class="panel-body"> <ul> <% #comment.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> </div> </div> <% end %> <div class="form-group"> <div class="control-label col-md-2"> <%= f.label :body, 'New Comment' %> </div> <div class="col-md-10"> <%= f.text_area :body, rows: 10, class: "form-control", placeholder: "New Comment" %> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <%= f.submit "Add Comment", class: "btn btn-primary btn-lg pull-right" %> </div> </div> <% end %> </div> How do I make this submit button save and redirect back to 'articles/:id'? Thanks in Advance.
The routes generated by in your router will look something like this: /articles/:article_id/comments/:id This means, when you need to load your article in the CommentsController, you should do something like this (as suggested by #Marlin): def set_article #article = Article.find(params[:article_id]) end Otherwise, you run the risk of attaching the comment to the incorrect article if there happens to be an ID collision between the IDs in the comments and article table. Or you simply get a ActiveRecord::RecordNotFound error. But I know, that this doesn't answer your question directly, ut I suspect that the issue is that you're loading the wrong record from the db somewhere because of the above mentioned. Try updating your code, and write a test, to make sure that you can programmatically reproduce the error :)
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
How can I in HAML nesting a div inside a loop?
I have this erb file: <div class="portlet-body"> <% #products.each_with_index do |product, idx| %> <% if (idx % 4) == 0 and idx > 0 %> </div> <% end %> <% if (idx % 4) == 0 %> <div class="row-fluid"> <% end %> <%= render :partial => 'products/small', :locals => { :product => product} %> <% end %> </div> How can I write this in HAML?
You can use each_slice to do things like this: .portlet-body - #products.each_slice(4) do |slice| .row-fluid - slice.each do |product| = render :partial => 'products/small', :locals => { :product => product}
Error after attempting to link_to partials
Using this previous question as a guide, I've attempted to create a ul navigation header above a container that renders partials within the container when clicked. (Hopefully that makes some sense, but it may not be important.) Until the links for the partials are clicked, I have it rendering a partial by default. However, when I went to click my link_to in hopes of rendering the partial I get the following error: uninitialized constant ProfileController I'm using Rails 3. Here's my relevant code: ProfilesController: def show_about #is_on_show_about = true end def show_info #is_on_show_info = true end views/profiles/show.html.erb: <div id="info"> <div id="infoContainer"> <% if #is_on_show_about %> <%= render :partial => 'show_about' %> <% elsif #is_on_show_info %> <%= render :partial => 'show_info' %> <% end %> <ul id="info"> <li> <%= link_to 'About', show_about_path, :remote => true %> </li> </ul> <ul id="settingsLinks"> <li>Advice</li> <li> <%= link_to 'Info', show_info_path, :remote => true %> </li> </ul> </div> <%= render :partial => 'show_about' %> Routes.rb: map.show_info 'profiles/:id/info', :controller => 'profile', :action => 'show_info' map.show_about 'profiles/:id/about', :controller => 'profile', :action => 'show_about' Can anyone help me fix this and explain what went wrong?
Both of your routes are incorrect. If your controller is indeed named ProfilesController (plural) then your routes should use :controller => 'profiles', instead of :controller => 'profile'.