Showing Spree taxonomy tree on product page - ruby-on-rails-4

I'm running Spree 2.2. I'm trying to get the standard taxonomy/filter list to appear on each individual product page in Spree, but I cannot find where it decides that there's sidebar content to be displayed. If anyone can shed any light on where/how that's decided I'd be most grateful.

On the front-end part of spree, more specific, on the index view of the products controller, route spree_frontend/app/views/spree/products/index.html.erb at the beginning of the file, it get's decided whether there will be displayed the taxons or not:
<% content_for :sidebar do %>
<div data-hook="homepage_sidebar_navigation">
<% if "spree/products" == params[:controller] && #taxon %>
<%= render :partial => 'spree/shared/filters' %>
<% else %>
<%= render :partial => 'spree/shared/taxonomies' %>
<% end %>
</div>
<% end %>
So what you can do is to write an override pointing at any part of the products/show view, in particular i suggest after the product_left_part_wrap" data-hook, wich is a wrapper for the sidebar on the products show view, so your deface could look something like this:
Deface::Override.new(
:virtual_path => 'spree/products/show',
:name => 'add_map_to_product_show',
:insert_after => '[data-hook="product_left_part_wrap"]',
:partial => "spree/products/the_taxons_and_filters"
)
And inside the file named _the_taxons_and_filters.html.erb located on app/views/spree/products/ you can add the code from above and include the taxons filters. Hope this was helpful.

Related

Rails 4, Draper: authenticated user and views

<% if user_signed_in? %>
<!-- lots of html/erb -->
<% end %>
This view pattern seems to not separate concerns.
I wrap several views in my app with logic demanding the user is signed in and would instead like to separate concerns and put the <% if user_signed_in? %> logic where it belongs...this seems like a decorator thing to me (hence the Draper tag).
What is best practice here?
Not sure understood your question, but try to answer.
At first to separate logic you dont need to use decorators in front of all, they serves for a little another thing.
To separate logic you can use simple partials depending on current user state, for ex:
<% if user_signed_in? %>
<%= render 'file_with_html_for_signed_user' %>
<% else %>
<%= render 'file_with_html_for_non_signed_user' %>
<% end %>
You can declare this statement in your layouts/application.html.erb

Use deface to change bad code in Spree store

I am working in Spree, and I am trying to use Deface to change this
<% if order.has_step?("delivery") %>
<div class="columns alpha four" data-hook="order-ship-address">
<h6><%= Spree.t(:shipping_address) %> <%= link_to "(#{Spree.t(:edit)})", checkout_state_path(:address) unless #order.completed? %></h6>
<%= render :partial => 'spree/shared/address', :locals => { :address => order.ship_address } %>
</div>
<% end %>
<% if #order.has_step?("delivery") %>
<div class="columns alpha four">
<h6><%= Spree.t(:shipments) %> <%= link_to "(#{Spree.t(:edit)})", checkout_state_path(:delivery) unless #order.completed? %></h6>
<div class="delivery">
<% order.shipments.each do |shipment| %>
<div>
<i class='fa fa-truck'></i>
<%= Spree.t(:shipment_details, :stock_location => shipment.stock_location.name, :shipping_method => shipment.selected_shipping_rate.name) %>
</div>
<% end %>
</div>
<%= render(:partial => 'spree/shared/shipment_tracking', :locals => {:order => #order}) if #order.shipped? %>
</div>
<% end %>
..into this.
<div class="columns alpha four" data-hook="order-ship-address">
<h6><%= Spree.t(:shipping_address) %> <%= link_to "(#{Spree.t(:edit)})", checkout_state_path(:address) unless #order.completed? %></h6>
<%= render :partial => 'spree/shared/address', :locals => { :address => order.ship_address } %>
</div>
I've already submitted a pull request about the redundant if statement and adding a data-hook to the second if #order.has_step?("delivery"), but in the meantime I need to write a deface override that will change the page to how I need it to look. I might be able to remove the first if #order.has_step?("delivery") since I think Deface will target the first instance of what I'm talking about on the page if I write
:remove => "erb[silent]:contains('if order.has_step?(\"delivery\"')")
although to be honest the documentation is not very good on that point. Anyway, how can I remove the entirety of the second if statement? There's no data-hook to target it, and using
:remove_content => "erb[silent]:contains('if order.has_step?(\"delivery\"')")
just removes the content of the first if statement. I can't target the first div in the second if statement since there's already a div class="columns alpha four" in the first if statement. I don't want to leave an empty div on the page, so what can I do?
The two if statements in the referenced code do not refer to the same variable. The first if refers to order, and the second to #order.
When using deface to remove existing sections of erb, the string passed in to contains must exactly match the code you want to move in order for the override to properly locate it. Since the second if statement uses #order, and your matcher doesn't include the # symbol, it won't remove that particular if statement.
Based on the rspec tests in the deface repo, it doesn't appear that you can currently use multiple matching strings with one override in the remove action. Instead, you'll have to use a second override to mach the second if statement and remove it.
The pull request I posted to Spree made this whole issue moot (which you can find here if you're interested: https://github.com/spree/spree/pull/5692 ). Also, it turns out that #order and order function in exactly the same way in that document, and all references to #order are in the process of getting removed from Spree anyway.

Indicate that an uploaded file is present in edit form -- paperclip

In my current solution, I am able to put a checkbox in the edit form so that users can delete attachment. However, there is no indication for the user that a file has been uploaded, the name of that file, etc. so that he can decide whether to delete.
Right now the form look like this. The first material is an existing one, the next 3 are due to
def edit
#post = Post.find(params[:id])
3.times { #post.post_materials.new }
end
As you can see, it's very hard to distinguish between them. Ideally, I want the first material file name to appear somehow.
<%= form_for #post, :html => { :multipart => true } do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
Materials:
<ul>
<%= f.fields_for :materials, :html => { :multipart => true } do |materials_form| %>
<li>
<%= materials_form.label :asset %>
<%= materials_form.file_field :asset %>
<%= materials_form.label :_destroy, class: "checkbox inline" do %>
Remove attachment <%= materials_form.check_box :_destroy %>
<% end %>
</li>
<% end %>
</ul>
<%= f.submit "Submit", class: "btn btn-large" %>
<% end %>
Running paperclip's generator creates a migration to add 4 attributes on your model, as you can see here. These attributes are:
<attachment>_file_name
<attachment>_file_size
<attachment>_content_type
<attachment>_updated_at
So, If you ran the generator this way: rails generate paperclip post_material asset, on your PostMaterial model, you will have these attributes:
asset_file_name
asset_file_size
asset_content_type
asset_updated_at
Then, on your code you can do something like this:
if materials_form.object.asset.exists? #object represents the current post_material instance
#show a label with object.asset_file_name
else
#render materials_form.file_field :asset
end

Rails - loops and routes, and getting . instead of /

I have three controllers, books, users and contributions. In a view in the books controller I have the following snippet -
<%= link_to contrib.user.username, show_users_path(contrib.user_id) %>
Which returns /users.n rather than /users/n
<%= link_to contrib.user.username, "users/#{contrib.user_id}" %>
does the same thing.
I've read SO questions about this problem with nested resources, and with custom routes, but I've simply got my routes set up as resources, as follows -
devise_for :users, :controllers => { registrations: 'registrations' }
resources :blogs
resources :books
resources :users
resources :contributions
In users/index I have the snippet
<%= link_to user.username, "users/#{user.id}" %>
which works fine. What is going on?
.....
The problem was I'm using an each loop. The whole snippet goes
<% if controller.controller_name == "books" %>
<p><strong>by <%=link_to book.user.username, book.user %></strong></p>
<% book.contributions.each do |contrib| %>
<p><%= link_to contrib.user.username, user_path(contrib.user) %></p>
<%end%>
<% end %>
I changed the fourth line to this -
<p><%= link_to contrib.user.username, user_path(book.contrib.user) %></p>
Which works. Can anyone explain why?
It's because the default path for the show action is object_path(object_id) - there i no default route called show_object_path - I was confusing the path with action.

Dropdown select list won't display items with custom forms of Zurb Foundation 4 and Rails 4

I've been having this annoying problem in which I click over a select dropdown input of my custom form, styled with Zurb Foundation 4 in my Rails application, and the list won't show its elements.
I thought at a start that was a problem with simple form, but I changed the f.association for f.collection_select, my code looks like this:
<h2><%= I18n.t(".sign_up") %></h2>
<%= simple_form_for(resource, :html => {:class => "custom"}, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= f.error_notification %>
<%= devise_error_messages! %>
<%= f.input :rut %>
<%= f.input :name %>
<%= f.input :email %>
<div>
<%= f.label :supplier_type_id %>
<%= f.collection_select :supplier_type_id, SupplierType.all, :id, :name %>
</div>
<%= f.input :password %>
<%= f.input :password_confirmation %>
<%= f.error :base %>
<%= f.submit I18n.t(".sign_up"), :class => "button" %>
<% end %>
<%= render "devise/shared/links" %>
The most strange thing is that sometimes I'm able to see the items when refreshing the page, but when I get to the page navigating from other view of the app then it won't work. I've also noticed this when using hints for forms (i.e: If I have two hints in the same form, in different inputs, only one would show, but the same one message displays in both inputs when each message should show in their respective input. When reloading the page sometimes it shows one hint, and sometimes the other)
The styling looks good, so I think that it might be a foundation javascript problem.
Another thing I've noticed is that when I load the page the styling does a kind of "blinking" when using custom forms. This blinking it looks likes foundation takes a while to load the styling, I've also noticed this on their own custom form documentation site. This may indicate that is a form styled with javascript events or something similar, so this might mean that javascript is working well.
In addition, the checkboxes are having a similar problem, they only can be checked just when you reload the page, it might have some relation with this problem.
I'm very lost, some help would become very handy. Thanks!
--edit: Foundation 5 doesn't include custom forms and works better--
You might need to refresh dropdowns on each page:change event. Try something like this:
$(document).on("page:change", function() {
// SELECTOR_TO_CUSTOM_DROPDOWNS should select any Zurb custom dropdowns you
// are using.
$(SELECTOR_TO_CUSTOM_DROPDOWNS).trigger("change");
});
That's from the documentation on Zurb custom form JS.
Yes, this is caused by turbolinks. It stops $(document).ready from firing on page load, which is required by foundation's custom forms.
Using ssorallen's answer and to be more unobtrusive than the OPs, add this to application.js:
$(function(){ $(document).foundation(); });
$(document).on("page:change", function() {
if ($('form.custom').length > 0) {
$(document).foundation('forms');
}
});
Also, if you have jquery/coffeescript that relies on document ready being fired, add jquery turbolinks to your Gemfile.
Ok, so I just figured out that I have repeated asset load on my browser. This is causing a javascript error. It appears that deleting in the manifest
//= require turbolinks
Solves the problem.
I solved my multiple asset problem changing
<%= javascript_include_tag "application" %>
To the head in my application layout.
After watching the turbolinks railscast I noticed that besides my multiple asset loading, turbolinks and foundation 4 may not be compatible, it might be a solution on this post. But still doesn't work perfect for me.
I also noticed that navbar is also affected by turbolinks.
I think that this is rather a turbolinks problem and not an specific foundation dropdown. I will close this question and open a new on turbolinks and foundation.
Thanks to some Nick Reed insights I found out that the foundation gem was initializing foundation in application.js like this:
$(function(){ $(document).foundation(); });
So I checked the docs and I used this:
<script>
$(document).foundation();
</script>
After the "/body" tag in the application layout and everything seems to be working like a charm!