I have a dropdown in the form i'm using
<%= f.select(:visitable_id) do %>
<% #visitors.each do |visitor| %>
<%= content_tag(:option, visitor.name, value: visitor.id, data: {:type => visitor.class.name.to_s} ) %>
<% end %>
<% end %>
When submitted I get the visitable_id in the controller. But I would also like to receive the data of the data value in the content_tag. The: data: {:type => visitor.class.name.to_s}
How can you access the second value in the controller? Any help would be appreciated!
HTML5 data attributes are not sent with the form. Nor is anything else except the name and value of the inputs.
You could solve it by passing both values through a single option.
<%= f.select(:visitable_id) do %>
<% #visitors.each do |visitor| %>
<%= content_tag(:option, visitor.name, value: "#{visitor.class.name}=visitor.id") %>
<% end %>
<% end %>
You can then parse them out by splitting the string:
klass, id = params[:visitable_id].split('=')
But make sure you whitelist the acceptable values for klass to avoid a vulnerability where a malicious user can query any model.
Related
I'm totally stuck on looping through a form.select in Rails (using Elastic Search/Searchkick aggs).
I can access the 'bucket' array (and thus "key" and "doc_count") when I don't pre-pend the form.select helper, but it just doesn't loop through when it's there. Not sure how I would get the options dynamically otherwise!
Does anyone know what might be going wrong (ignore the link_to stuff, I'll be changing that once I can get the actual "key")? Perhaps I'm using the form.select helper incorrectly? Thanks!
<% form.select #jobs.aggs["location"]["buckets"].each do |bucket| %>
<% if params[:location] == bucket["key"].to_s %>
<strong><%= link_to bucket["key"], request.params.except(:location)%></strong>
<% else %>
<%= link_to bucket["key"], request.params.merge(location: bucket["key"])%>
<% end %>
<% end %>
I figured it out! It was a syntax error on my part, as I forgot to use :location in the first part of the form.select, and additionally didn't wrap the block after this in [] brackets (presumably the options have to be in an array or hash with this helper).
Here is the code (simplified) which solved this for me:
<% form.select :location, [#jobs.aggs["location"]["buckets"].each do |bucket| %>
<%= bucket["key"] %>
<% 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 have the following form:
<%= form_tag classification_code_rules_path do %>
<% #classification_code_rules.each do |rule| %>
<%= fields_for "classification_code_rule[]", rule do |pf| %>
<%= pf.text_field :name %>
<% end %>
<% end %>
<%= submit_tag %>
<% end %>
It sends what I want to the server:
Parameters: { ... "classification_code_rule"=>[{"name"=>"dasdsaf"}, {"name"=>"sfsdgdfhgf"}, {"name"=>"hfghfgjhgjhg"}], "commit"=>"Save changes"}
Since classification_code_rule is an array, I handle the params as follows:
def classification_code_rule_params
params[:classification_code_rule].each do |rule_param|
rule_param.permit!
end
end
But I am getting the following error:
When assigning attributes, you must pass a hash as an argument.
How can I handle this situation where the strong param is an array?
Try something like this
params.require(:classification_code_rule).map do |rule_param|
ActionController::Parameters.new(rule_param.to_hash).permit!
end
Using Rails 3. This is a front-end design question.
Goal:
Contact | Email | URL
show.html.erb:
<% if !#shop.contact.blank? %>
<%= #shop.contact %>
<% end %>
<% if !#shop.email.blank? %>
<%= #shop.email %>
<% end %>
<% if !#shop.url.blank? %>
<%= link_to #shop.url, #shop.url, :target => "_blank" %>
<% end %>
How do I put in | only when the previous and after element has values? At current stage, if there is no value, nothing is output.
Many thanks.
<% url = link_to(#shop.url, #shop.url, :target => "_blank") if #shop.url.present? %>
<%= [#shop.contact, #shop.email, url].select(&:present?).join(" | ") %>
This creates an array of all your elements, selects those which have a value (as present? is the opposite of blank?) and then joins each element of the remaining array by putting a pipe between them.
That said, if you have more complex logic, you should probably create a helper method. The ERB templates are not a good place for complex logic. This above is bordering acceptable.
I have an action in the controller:
def user_detail
#user_detail = UserDetail.find_by_id(11)
end
And in the view:
<%= #user_detail -%> // displays me like #
I am trying to retrieve the contents of #user_detail: actually the hash contains {:empid=>"11111", :prjtname=>"aaaaa", :prjtrole=>"Developer"}
How do I display the user detail's empid and other values?
Since I know what question you asked earlier, I think this is the syntax you actually want to use:
<%= #user_detail.additional_info[:empid] %>
Unless of course you renamed the name of the hash :)
Another approach, if you want all the content from the hash but the keys varies from each record, you could loop through them like this:
<% #user_detail.additional_info.each_pair do |key, value| %>
<p>Key: <%= key %> Value: <%= value %></p>
<% end %>
To get simple debug output like the example you posted, this will handle it:
<%= #user_detail.inspect %>
try this <%= #user_detail.emplid %> <%= #user_detail.prjtname %> <%= #user_detail.prjtr %>
More of an extraction from #dln's answer
try using
<%= #user_detail[:emplid] %>
<%= #user_detail[:prjtname] %>
<%= #user_detail[:prjtr] %>
Hope this solves your prob