I have a dashboard with a date range, the user can search activy for the period he wants.
I have different models that I manage with the same Dasboard
For example I want to find:
the users registration in a date range
the sales in a date range
etc...
I have buttons that represent the models, on click they render the appropriated partial.
I can search for date range but it only works for the first partial sales in this case, if I click on the next button which is users the search redirect on the first partial sales
This is because the dashboard action show renders by default sales I would need something that renders the current active button...
Could you help please me to find how to do this?
below some code:
dashboard.rb
class Dashboard
attr_reader :date_from, :date_to
def initialize(params)
params ||= {}
#date_from = parsed_date(params[:date_from],Time.now.beginning_of_month.to_date.to_s)
#date_to = parsed_date(params[:date_to], (Date.today + 1).to_s)
end
def article_date_range
Article.where('created_at BETWEEN ? AND ?', #date_from, #date_to)
end
private
def parsed_date(date_string, default)
Date.parse(date_string)
rescue ArgumentError, TypeError
default
end
end
the show action in dashboards_controller.rb
def show
#button ||= set_button || :sales
#dashboard = Dashboard.new(params[:search])
#articles = #dashboard.article_date_range
#articles = #articles.order('created_at ASC')
end
private
def set_button
button = dashboard__params[:button]&.to_sym and [:sales, :users].include?(button) and button
end
this form and buttons are in the dashboard show.html.erb
<%= form_tag admin_dashboard_path, method: :get do %>
<%= text_field_tag "search[date_from]", #dashboard.date_from, class: "datepicker" %>
<%= text_field_tag "search[date_to]", #dashboard.date_to, class: "datepicker" %>
<%= submit_tag "Rechercher", class: "btn btn-main" %>
<% end %>
#the buttons that "redirect" to the appropriated partial
<% [:sales, :users, :articles].each do |button| %>
<li class="tabs list-inline-item <%= params[:button] == button.to_s ? "tabs__item--active" : "tabs__item--inactive" %>">
<%= link_to admin_dashboard_url(button: button) do %>
<%= button.capitalize %>
<% end %>
</li>
<% end %>
Update
The idea is that the user select a date range and then click on the buttons to see the activity in the selected date range for either articles sales and users (without selecting again the date range)
I think this is because, dashboard__params[:button] is always nil. Because in your search form there is no input field with name set to button. If you are thinking about <%= link_to admin_dashboard_url(button: button) do %>, it's outside the html form.
So method set_button is returning nil.
So the first line of your show action always returns :sales as this is the default value if set_button returns nil.
I would suggest to add an hidden input field in your search form. Then use javascript to prevent the default form submit behavior, set the value of that hidden input field with appropriate value (sales or user), then submit the form using javascript.
Update 1
show.html.erb
<%= form_tag admin_dashboard_path, method: :get do %>
<%= text_field_tag "search[date_from]", #dashboard.date_from, class: "datepicker" %>
<%= text_field_tag "search[date_to]", #dashboard.date_to, class: "datepicker" %>
<%= hidden_field_tag 'button', 'sales', id: 'button' %>
<%= submit_tag "Rechercher", class: "btn btn-main" %>
<% end %>
#the buttons that "redirect" to the appropriated partial
<% [:sales, :users, :articles].each do |button| %>
<li class="tabs list-inline-item <%= params[:button] == button.to_s ? "tabs__item--active" : "tabs__item--inactive" %>">
<%= link_to admin_dashboard_url(button: button) id: "#{button}_click" do %>
<%= button.capitalize %>
<% end %>
</li>
<% end %>
Now using javascript before submitting the search form, set the value of the hidden_filed.
Update 2
show.html.erb
<%= link_to '#', id: "#{button}_click", class: 'model_link' do %>
<%= button.capitalize %>
<% end %>
javascript (assuming you have jQuery)
$(document).ready(function() {
$('.model_link').click(function() {
var buttonName = $(this).attr('id').split('_')[0];
$('#button').val(buttonName);
$('form').submit();
});
});
Related
Sort of new in rails so i might be doing things the wrong way
show.html.erb:
<% #feature.each do |p| %>
<br>
<h1><%= p.name %></h1>
<%= p.unit_price %>
<%= render partial: "shared/featureuse_form", locals: {feat_use: #feat_use , feature: p} %>
<%= button_to'Change' , feature_use_path(1) , :class => 'btn btn-primary' ,method: :delete %>
<% end %>
Right here in feature_use_path how do i get an id to pass it in order to make a delete button as i havent even created the model yet or its saved in its own controller should
_featureuse_form.html.erb:
<%= form_with model: feat_use do |f| %>
<%= f.number_field :total_units ,value: feature.max_unit_limit %>
<%= f.hidden_field :feature_id, value: feature.id %>
<%= f.hidden_field :usage_id, value: current_user.usage.id %>
<%= f.submit "confirm", id: "button"%>
<% end %>
Plans Controller
class PlansController < ApplicationController
before_action :authenticate_user!
def index
#plan = Plan.all
end
def show
#plan = Plan.find(params[:id])
#feature = #plan.features
#feat_use = FeatureUse.new
end
end
class FeatureUsesController < ApplicationController
def create
feature_use = FeatureUse.new(feature_use_params)
feature_use.total_units = params[:feature_use][:total_units]
feature_use.feature_id = params[:feature_use][:feature_id]
user = current_user.usage
feature_use.usage_id = user.id
feature_use.save
end
end
You're right that you can't create a button (method: :delete or otherwise) that relies on a record that doesn't yet exist.
Usually, a button like this would only be relevant to existing records anyway.
So, it's common to see an if statement like this:
<% if #feature_use.persisted? %>
<%= button_to 'Change' , feature_use_path(#feature_use.id) , :class => 'btn btn-primary', method: :delete %>
<% end %>
.persisted? returns false if the record is new and un-saved.
I am trying to create a search page that searches through the model courses. Courses has a "name" column that lists the names of courses. I created a search controller and this is what I have on my search controller:
class SearchController < ApplicationController
def search
if params[:search].blank?
redirect_to(root_path, alert: "Empty field!") and return
else
#parameter = params[:search].downcase
#results = Courses.all.where("lower(name) LIKE :search", search: #parameter)
end
end
def show
render 'search'
end
end
I have under views/search a search.html.erb page. On this page I have
<%= form_tag(search_path, :method => "get",
class: 'navbar-form navbar-left') do %>
<div class="input-group">
<%= search_field_tag :search, params[:search], placeholder: "Search", class: "form-control" %>
<div class="input-group-btn">
<%= button_tag "", :class => 'btn btn-info glyphicon glyphicon-search',:name => nil%>
</div>
</div>
<% end %>
<h3>Search Result</h3>
<% #results.each do |result| %>
<%= result.name %><br>
<% end %>
However, I am getting the following error when I run my rails server and click on search and I am not sure why #results is null. Thanks for the help!
11: <h3>Search Result</h3>
12:
13: <% #results.each do |result| %>
14: <%= result.name %><br>
15: <% end %>
When the form provided in app/views/search/search.html.erb is submitted, the request is sent to show action by default. But the show action just renders the search view, no #results is assigned and the error occurs.
The search action seems unnecessary and you should use the show action instead. For example, rename app/views/search/search.html.erb to app/views/search/show.html.erb and move the search code to show action as below:
app/controllers/search_controller.rb
class SearchController < ApplicationController
def show
if params[:search].blank?
redirect_to(root_path, alert: "Empty field!")
else
#parameter = params[:search].downcase
#results = Courses.all.where("lower(name) LIKE :search", search: #parameter)
end
end
end
I'm learning Spree 3.0 and I have a setup a test shop that sells shorts.
Shorts has multiple option types: Size, Color, Length
I wanted to change the way it displays the variant options on the frontend from a radio checkbox to a drop down box.
Currently, Spree displays the option types as radio buttons:
I want to change this to use drop down menus for each option type, like this:
I've tried the following:
<%= select_tag "variant_id", options_for_select(#product.variants_and_option_values(current_currency).collect{ |v| ["#{variant_options(v)} #{variant_price(v)}", v.id] })%>
But it simply displays the values of all option types in each tag:
I wanted to know the best way to split the option values into individual dropdown menus?
Any assistance is my much appreciated, thank you.
This is not as easy as it looks since you will be using Spree::OptionValue records instead of variants and at some point you will want to convert back to variants in order to add it to your cart. Combinations might not be possible and/or out of stock so it is highly unpractical to work with option_values.
But nonetheless, you wanted to know how so i set up the following:
#options = Spree::OptionValue.joins(:option_value_variants).where(spree_option_value_variants: { variant_id: #product.variant_ids }).group_by(&:option_type)
This will give you a hash with the keys of the hash being option_types (Size, Color, Length in your case) and the values being arrays of option_values.
You can easily form this into radios like this:
<% #options.each do |option_type, option_values| %>
<%= content_tag :h2, option_type.presentation %>
<% option_values.each do |option_value| %>
<%= radio_button_tag option_type.name, option_value.id %>
<%= label_tag option_value.presentation %>
<% end %>
<% end %>
Or for dropdowns:
<% #options.each do |option_type, option_values| %>
<%= content_tag :h2, option_type.presentation %>
<%= collection_select :variants, option_type.name, option_values, :id, :presentation %>
<% end %>
And in your controller you would want to find a variant matching those 3 criteria, check if it is in_stock, backorderable or track_inventory? is false and respond with errors or an updated cart :)
I hope this helped
This is what I did to solve this problem. It basically takes the variant_id parameter that was controlled by the radio buttons and turns it into a hidden field controlled by jQuery and AJAX with additional notifications.
I hope this helps someone.
config/routes.rb
# Mount the core routes
Rails.application.routes.draw do
mount Spree::Core::Engine, at: '/'
end
# Create new routes
Spree::Core::Engine.routes.draw do
post "products/:product_id/get_variant",
to: "products#toggle_like",
as: "get_variant",
constraints: { :format => /(js)/ }
end
app/models/spree/product_decorator.rb
Spree::Product.class_eval do
# Find the Product's Variant from an array of OptionValue ids
def find_variant_by_options(array)
option_values = Spree::OptionValue.where(id: array)
variants = []
option_values.each do |option_value|
variants.push(option_value.variants.ids)
end
self.variants.find_by(:id => variants.inject(:&).first)
end
end
app/controllers/spree/products_controller_decorator.rb
Spree::ProductsController.class_eval do
# Get the Variant from params[:ids], respond with JavaScript
def get_variant
#product = Spree::Product.find_by :slug => params[:product_id]
#variant = #product.find_variant_by_options(params[:ids].split(','))
respond_to do |format|
format.js
end
end
end
app/views/spree/products/get_variant.js.erb
// Update hidden field #varient_id's value.
$("#variant_id").val("<%= #variant.id %>")
// Update price
$(".price.selling").html("<%= number_to_currency #variant.price %>");
<% if #variant.in_stock? && #variant.available? %>
// If in stock and available
$("#add-to-cart-button").prop("disabled", false); // Enable button
$(".out-of-stock").hide(); // Hide 'out of stock' message
<% else %>
// Otherwise
$("#add-to-cart-button").prop("disabled", true); // Disable button
$(".out-of-stock").show(); // Show 'out of stock' message
<% end %>
app/views/spree/products/_cart_form.html.erb
<%= form_for order, url: populates_orders_path do |f| %>
...
<% if #product.variants_and_option_values(current_currency).any? %>
<div id="product_variants" class="col-md-6">
<h3 class="product-section-title"><%= Spree.t(:variants) %></h3>
<% #product.option_types.each do |option_type| %>
<%= f.label "option_type_#{option_type.id}", option_type.name %>
<br>
<%= f.select "option_type_value_#{option_type.id}",
option_type.option_values.all.collect { |v| [ v.name, v.id ] },
{ include_blank: true },
{ class: "form-control" } %>
<br>
<% end %>
<%= hidden_field_tag "variant_id", value: "0" %>
...
</div>
<% else %>
<%= hidden_field_tag "variant_id", #product.master.id %>
<% end %>
...
<span class="price selling"
itemprop="price"
content="<%= #product.price_in(current_currency).amount.to_d %>">
<%= display_price(#product) %>
</span>
...
<%= button_tag class: "btn btn-success",
id: "add-to-cart-button",
disabled: #product.variants.any?,
type: :submit do %>
<%= Spree.t(:add_to_cart) %>
<% end %>
...
<span class="out-of-stock" style="display: none;">
<%= Spree.(:out_of_stock) %>
</span>
<% end %>
<script>
// Call AJAX if all options are selected, otherwise clean up.
$("#product-variants select").change(function(){
var option_value_ids = [];
$("#product-variants select").each(function(){
option_value_ids.push($(this).val());
});
if(option_value_ids.indexOf("") == -1){
$.ajax({
url: "<%= get_variant_path(#product) %>?ids=" + option_value_ids.join(','),
method: "post"
});
}else{
$("#variant_id").val("0");
$("#add-to-cart-button").prop("disabled", true);
$(".out-of-stock").hide();
}
});
</script>
I want site visitors to be able to view nearby shows within a radius that can be input via dropdown form. I have a view that displays nearby shows using the Geocoder gem:
<h3> Shows near <%= request.location.city %> </h3>
<%= form_for #nearby_shows.first do |f| %>
<p> Radius (in miles): <%= f.select(:radii, [10,20,30,40,50], {},
:style => "width:50px", :selected => f.object.radii, :onchange =>
"location.href = '#{shows_path}'") %> </p>
<% end %>
<ul class="users">
<% #nearby_shows.each do |nearby_show| %>
<li>
<%= link_to nearby_show.show_name, nearby_show %>
</li>
<% end %>
</ul>
Right now the selection doesn't affect anything, and the selection isn't remembered in the form when the page refreshes.
The model, show.rb contains:
attr_accessor :radii
And the shows controller contains:
def index
#shows = Show.all
#radii = 50
#nearby_venues = Venue.near("Boulder, CO",#radii,:select =>
"id").to_a
#nearby_shows = Show.where(show_venue: #nearby_venues)
end
In production, I'll be using request.location.city, but in development I'm just using "Boulder, CO" as an example.
How can I set #radii using the input select form? I am concerned that form_for will not permit me to change a variable for the list of entities #nearby_shows.
If you want a fast AJAX solution, here's what I would do
First, add an ID to your list so it's easy to manipulate
<ul id="my_id" class="users"></ul>
I really don't understand why you need that <%= form_for #nearby_shows.first %> for ? If I understand well, you just want to show a select, and update the list of nearby shows based on what the user selects ?
routes.rb
resource :shows do
get 'update_nearby', on: :collection, constraints: { format: 'js' }
end
# GET /shows/update_nearby, meant to be used only with AJAX
your_view.html.erb
<%= form_tag update_nearby_shows_path, remote: :true do |f| %>
<p> Radius (in miles): <%= select_tag(:radii, [10,20,30,40,50], {},
:style => "width:50px", :selected => #radii, :onchange =>
"location.href = '#{shows_path}'") %> </p>
<% end %>
<!-- On Submit, it will request a JS response
You can add some JS to submit the form everytime the select changes -->
Add some JS specific respone
your_controller.rb
def update_nearby
find_nearby_shows
end
private
def find_nearby_shows
#radii = params[:radii] ? params[:radii] : 50
#nearby_venues = Venue.near("Boulder, CO",#radii,:select =>
"id").to_a
#nearby_shows = Show.where(show_venue: #nearby_venues)
end
update_nearby.js.erb
<% if #nearby_shows %>
// Empty the list
var id = $("#my_id").empty()
<% #nearby_shows.each do %>
// Add one <li> per show
$("<li>", { 'html': "<%= escape_javascript(link_to(nearby_show.show_name, nearby_show)) %>"}).appendTo(id)
<% end %>
<% end %>
Bonus : you said you wanted to save the radius ? You can actually try to add it to the user session
def index
...
#radii = session[:saved_radii] ? session[:saved_radii] : DEFAULT_RADIUS
...
end
def update_nearby
find_nearby_shows
session[:saved_radii] = #radii
end
But if you really want to save it for the user, you should have a preferred_radii field in your User model
Everything is posting correctly, but I do not see any labels in my checkboxes, just blanks. My form looks like this:
<%= form_for #itemrecord do |f| %>
<div class="col-xs-12">
<p><b>Items people are asking for</b></p>
</div>
<% #wishlist.each do |category, list| %>
<div class="col-xs-2">
<div class="form-group box">
<h5> <%="#{category}"%> </h5>
<% list.each do |thing| %>
<%= check_box_tag ":item_name[]", "#{thing}" %>
</br>
<% end %>
</div>
</div>
<% end %>
<%= f.submit "Go!", class: "btn btn-primary btn-large btn-block" %>
</div>
<% end %>
What's happening is that wishlist is a hash of categories and items within those categories that I set in the controller, and is then called by multiple form builders to build checkboxes. The challenge is that right now in the current implementation, the checkboxes params are passed through properly (FYI controller code is at the bottom), but beside each checkbox, there is no text that shows the thing (i.e., no label so that people know what they're checking.
Here's the html generated for one checkbox (it's the same for all checkboxes)
Basically, I need to make the value the label.
FYI what's happening is that for every item checked, a record is being created. Here's the controller code:
def create
items_to_be_saved = []
inventory_params.each do |i|
items_to_be_saved << ({ :signup_id => Signup.find_by_email(session[:signup_email]).id, :item_name => i })
end
if Inventory.create items_to_be_saved
flash[:success] = "Thanks!"
redirect_to root_path
else
render new_inventory_path
end
end
def inventory_params
params.require(":item_name")
end
In your code:
<%= check_box_tag ":item_name[]", "#{thing}" %>
Second parameter for check_box_tag is not a label value, it is just a value which goes to controller in parameters. If you wan't to display label within your checkbox you will need to call label_tag in your view:
= label_tag ':item_name[]', thing
= check_box_tag ':item_name[]'
But you definitely should check simple_form gem which allows you to render checkboxes in much cleaner way:
f.input :field, as: :boolean, inline_label: 'Label'
can you please try it and let me know
<%= check_box_tag 'item_name[]', thing %>