On Rails 4. I'm working on an e-commerce app where a user can choose to go through a wizard-like process.
First the user selects a color scheme,
then selects products from two different pages,
then the results of those product selections are displayed on a fourth page.
No rows are created or updated in the database, I just want the results to be displayed on the fourth page (because this info is then fed to a third-party service).
Because the array would be no more than five or six choices, I am passing the product ids through the URL params. Here's the controller (let's say on the second page the user selects paper products and on the third page the user selects pencil products)
class WizardController < ApplicationController
def index
# Where the user clicks on a color scheme link
end
def paper
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
end
def paper_submit
respond_to do |format|
format.html { redirect_to wizard_pencils_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
id: params[:ids]) }
end
end
def pencils
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
#paper = Product.find(params[:id])
end
def pencils_submit
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
id: params[:ids] + [:paper_ids]) } # ?? Not sure what goes here
end
end
def finish
# Haven't gotten here yet
end
private
def color_scheme_params
params.require(:wizard).permit(:color_scheme_id, :id)
# Also not too sure about this area either
end
end
Routes:
get '/wizard/paper', controller: 'wizard', action: 'paper'
put '/wizard/paper', controller: 'wizard', action: 'paper_submit'
get '/wizard/pencils', controller: 'wizard', action: 'pencils'
put 'wizard/pencils', controller: 'wizard', action: 'pencils_submit'
get '/wizard/finish', controller: 'wizard', action: 'finish'
resources :wizard
Form for the second page (selecting paper products)
<%= form_for([#color], html: {multipart: true}, url: {action: "paper_submit"}, method: 'put') do |f| %>
<%= f.hidden_field(:color_scheme_id, value: #color.id) %>
<div class="row">
<% #product.where(enabled: true, color_scheme_id: #color).each do |product| %>
<% if product.tags.where(name: "Paper").count > 0 %>
<div class="col-lg-3 col-md-4 col-sm-6">
<%= check_box_tag 'ids[]', product.id -%>
<%= link_to image_tag(product.thumbnail.url(:thumbnail_small_opt), alt: product.name), product %>
<p><%= link_to product.name, product %>, $<%= product.price %></p>
</div>
<% end %>
<% end %>
</div>
<div class="row">
<div class="col-lg-12">
<p style="text-align:right;"><%= f.submit "Next: Select Pencils", class: "btn bg-primary" %></p>
</div>
</div>
<% end %>
So far this all works fine. But, the problem is when the user makes product selections on the third page and reaches the fourth page. Ideally I want my application to combine the product id params from the second page with the different product ids from the third page.
<%= form_for([#color], html: {multipart: true}, url: {action: "embellishments_submit"}, method: 'put') do |f| %>
<%= f.hidden_field(:color_scheme_id, value: #color.id) %>
<!-- A hidden field maybe?? This does not work though -->
<%= f.hidden_field(:paper_ids, multiple: true, value: #paper) %>
<div class="row">
<% #product.where(enabled: true, color_scheme_id: #color).each do |product| %>
<% if product.tags.where(name: "Pencil").count > 0 %>
<div class="col-lg-3 col-md-4 col-sm-6">
<%= check_box_tag 'ids[]', product.id -%>
<%= link_to image_tag(product.thumbnail.url(:thumbnail_small_opt), alt: product.name), product %>
<p><%= link_to product.name, product %>, $<%= product.price %></p>
</div>
<% end %>
<% end %>
</div>
<div class="row">
<div class="col-lg-12">
<p style="text-align:right;"><%= f.submit "Next: Purchase Your Selections", class: "btn bg-primary" %></p>
</div>
</div>
<% end %>
It seems like a simple thing, I just want to combine an array from two different pages from the URL params but I can't figure out how to do this. Don't really want to use a gem for this because this is all I need to figure out. Thanks for any help.
Just put your variables into session:
def paper_submit
session[:paper_ids] = params[:ids]
respond_to do |format|
format.html { redirect_to wizard_pencils_path(
color_scheme_id: params[:color_scheme][:color_scheme_id]
) }
end
end
def pencils
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
#paper = Product.find(params[:id])
end
def pencils_submit
session[:pencil_ids] = params[:ids]
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id]
) }
end
end
def finish
#all_products = Product.where(
enabled: true,
color_scheme_id: params[:color_scheme_id],
id: session[:paper_ids] + session[:pencil_ids]
)
end
finish.html.erb:
<% #all_products.each do |product| %>
<%= product.name %>
<br />
<% end %>
You should add those two arrays and make something like:
def pencils_submit
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
product_ids: params[:ids] + [:paper_ids]) }
end
end
Then in your form:
<% #product_ids.each do |id| %>
<%= f.hidden_field_tag 'product_ids[]', id %>
<% end %>
Then in your last finish action do whatever you want.
Related
My application has a Micropost model and a Comment model.
I introduced in the Micropost partial links for showing/hiding and refreshing comments:
<li id="micropost-<%= micropost.id %>">
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
<span class="content">
<%= micropost.content %>
<%= image_tag micropost.picture.url if micropost.picture? %>
</span>
<% if micropost.comments.any? %>
~ <%= link_to "Show/hide comments", "#", class: "comments-link", remote: true %>
~ <%= link_to "Refresh comments", fetch_comments_path(micropost), remote: true %>
<% end %>
<% if logged_in? && (current_user == micropost.user || current_user.friend?(micropost.user)) %>
<div class="comment-section">
<%= form_for(current_user.comments.build, remote: true) do |f| %>
...
<% end %>
</div>
<% end %>
<div class="comments-section">
<% if micropost.comments.any? %>
<ol id="comments_micropost-<%= micropost.id %>">
<% micropost.comments.each do |comment| %>
<%= render comment %>
<% end %>
</ol>
<% end %>
</div>
</li>
This links are added to the page after creating the first comment and are loaded if the micropost has comments.
However, in case there is just one comment and it is deleted, they are useless so I would like to remove them with Ajax via the destroy action of the comments controller.
I am having my troubles to realize this.
The main problem is that I cannot refer to the micropost using the to-be-destroyed comment.
Once the comment is destroyed any #micropost = #comment.micropost association would return a nil object:
def destroy
#comment = current_user.comments.find_by(id: params[:id])
#micropost = #comment.micropost
#comment.destroy
respond_to do |format|
format.html do
flash[:success] = "Comment deleted"
redirect_to request.referrer || root_url
end
format.js
end
end
Thus, inside create.js.erb I cannot use a if #micropost.comments.nil? remove links conditional
Moving #comment.destroy after the respond_to block would not work for format.html, without refreshing the page.
If it worked, I could use a if #micropost.comments.count == 1 remove links conditional in create.js.erb
I cannot move #comment.destroy inside the format.html block, because it would not be used by format.js.
What solution can I use?
The delete link in the comment partial is:
<%= link_to "delete", comment, method: :delete, remote: true %>
Is it possible to pass in link_to a params value equal to micropost.id, such as:
<%= link_to "delete", comment, method: :delete, micropost_id: micropost.id, remote: true %>
so that I can write in the destroy action:
#micropost = Micropost.find(params[:micropost_id]) ?
When you destroy your object it is destroyed form database and all reference keys are destroyed immediately. So you can first grab post Id and the remove comment.
def destroy
#micropost_id = #comment.micropost.id
#comment.destroy
end
Now you can use #micropost_id to take another action or to redirect to the parent post like this:
redirect_to '/microposts/'+ #micropost_id
Or
redirect_to MicroPost.find(micropost_id)
When I attempt to add an item to the cart, it works but nobody can see it directly because the page is not reloading. How can I fix it ?
Here's my order_item_controller :
class OrderItemsController < ApplicationController
def create
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.save
session[:order_id] = #order.id
end
and my views/product, with form_for :
<%= form_for order_item, remote: true do |f| %>
<%= product.firstdescription %>
<p class="bonus1">-Durée du cours : <%= product.duration %> minutes</p>
<p class="bonus">-<%= product.info %>
<p class="bonus">-En préparation</br>
<div class="talent">
<%= f.hidden_field :quantity, value: 1, class: "form-control", min: 1, max: 1 %>
<%= f.hidden_field :product_id, value: product.id %>
<div class="on_precommand">
<p id="old_price">
<del><%= currency_euro product.old_price %></del>
</p>
<p><%= currency_euro product.price %></p></br>
<%= product.tournage %></br>
</div>
<%= f.submit "Pré-commander", class: "addtocart" %>
<% end %>
All you need to do is a simple redirect, add this line at the end of the action
redirect_to #order
This will redirect to the show action of the new order.
EDIT:
Just noticed you are doing a remote: true request, so instead you need to create a js template create.js.erb for example, and add the javascript you want to be executed to add the created order in the view, here's an example:
$('#orders').append('<%= j( render #order ) %>')
Of coruse this is assuming that the orders div is has an id #orders
My users have reviews, review may be negative and positive
And now i want show positive and negative reviews for other users
users_controllers.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#reviews = Review.where(for_user_id: #user, negative: false)
#reviews = #reviews.where(negative: params[:negative]) if params[:negative].present?
#reviews = #reviews
end
end
and my view
views/users/show.html.erb
<%= link_to 'Negative reviews', user_path(negative: true) %>
<%= link_to 'Positive reviews', user_path(negative: false) %>
<% #reviews.each do |review| %>
<li>
<div class="user_data">
<div class="user_review_left">
<%= link_to (avatar_for review.user, size: "50x50"), review.user %>
</div>
<div class="user_review_right">
<%= link_to review.user.name, review.user %>
<div class="user_post_name">
review for: <%= link_to (truncate review.post.name, length: 50), review.post %>
</div>
</div>
</div>
<div class="post_review">
<%= review.body %>
</div>
<div class="review_date">
<%= l review.created_at, :format => :my %>
</div>
</li>
<% end %>
</ul>
</div>
how i can add links for this code?
if user link the controller return #reviews with params
Thanks
<%= link_to 'Negative reviews', user_path(#user, negative: true) %>
and
<%= link_to 'Positive reviews', user_path(#user, negative: false) %>
and change your show method:
def show
#user = User.find(params[:id])
#reviews = Review.where(for_user_id: #user, negative: (params[:negative] || false))
end
even if I ask myself why you can't do that:
def show
#user = User.find(params[:id])
#reviews = #user.reviews.where(for_user_id: #user, negative: (params[:negative] || false))
end
You could pass the user ID and the review parameter
link_to "Reviews", user_path(id: #user.id, negative: true)
As said by coorase appending a parameter to the end of the args will work.
<%= link_to 'Negative reviews', user_path(#user, negative: true) %>
will create a url like: root/users/:id?negative=true
if you debug inside of the controller action which handles this and evaluate the value of 'params' you will see something like:
{"negative"=>"true", "controller"=>"root", "action"=>"index"}
this is your params hash and it means that
params[:negative] ==> true
(I recommend getting the 'pry' gem and inserting 'binding.pry' inside the controller action if you don't have a good debugger you use)
Please be more specific in explaining why this output doesnt work for your situation and I may be able to help you formulate better parameters
So just got some help on this, but now have a new issue...I'm trying to list all of the 'commits' (these are basically simple edits) for a certain project. This is currently working but when I try to list the user who created the commit it is showing the wrong user profile picture (or name, etc). What is happening is the person who created the project is currently also the user_id for all commits.
i.e, User A creates the project...then User B comes and adds a commit. But its showing User A as the profile pic for ALL commits for some reason, and I can't quite figure out why. This must have something to do with the 'new' or 'create' methods for commits because its always associating the new commit with the user who created the project (when it should be associating the commit with the current_user).
Thanks in advance for any help...
COMMITS CONTROLLER
class CommitsController < ApplicationController
before_action :find_project
def new
#commit = #project.commits.build(user_id: #project.user_id)
end
def show
#project = Project.find(params[:project_id])
#commit = Commit.find(params[:id])
end
def index
# #user = User.where(:id => #commit.user_id) first figure out how to set user_id on new commits (its nil now)
#commits = Commit.paginate(page: params[:page])
end
def create
#project = Project.find(params[:project_id])
#commit = #project.commits.build(commit_params)
if #commit.save
flash[:success] = "You've successfully committed to this project"
redirect_to project_path(#project)
else
render 'new'
end
end
def edit
end
def update
end
def destroy
end
private
def find_project
#project = Project.find(params[:project_id])
end
def commit_params
params.require(:commit).permit(:title, :project_id, :user_id)
end
end
NEW.HTML.ERB (NEW COMMITS FORM)
<div class="row-fluid">
<div class="col-md-5 no-pad">
<h1>Commit a new session file to this project repository</h1>
<%= bootstrap_form_for #commit, :url => project_commits_path do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_field :title %>
<%= f.hidden_field :user_id %>
<div class="well">
<h4>Drag and Drop a file here:</h4>
<%= image_tag("wavicon-large-grey.png", alt: "add file") %>
</div>
<%= f.button "Commit Now! ", class: "btn btn-lg btn-primary" %>
<% end %>
</div>
<div class="col-md-1">
<%= image_tag "shadow-vert.png" %>
</div>
</div>
INDEX.HTML.ERB (list of project commits showing incorrect user profile pic)
<% provide(:title, #commits ) %>
<div class="row-fluid">
<section class="no-pad col-md-9">
<%= render :partial => '/projects/project_header' %>
<h4>Commit History</h4>
<%= will_paginate %>
<ul class="commits">
<% #project.commits.first(5).each do |commit| %>
<%= render partial: "commit", object: commit %>
<% end %>
</ul>
<%= will_paginate %>
</section>
</div>
_COMMIT.HTML.ERB PARTIAL (referenced above)
<li>
<%= link_to project_commit_path(#project, commit) do %>
<h6><%= image_tag commit.user.image_url(:thumb).to_s, :class => "profile-pic-thumb" %><%= commit.title %>...</h6>
<span class="timestamp pull-right">
Created <%= time_ago_in_words(commit.created_at) %> ago
<span class="glyphicon glyphicon-time"></span>
</span>
<% end %>
</li>
Where am I going wrong? This code below should be showing the user who created the 'commit'...not the user who created the 'project'.
<h6><%= image_tag commit.user.image_url(:thumb).to_s, :class => "profile-pic-thumb" %><%= commit.title %>...</h6>
Update the new action as below:
def new
#commit = #project.commits.build(user_id: current_user.id)
end
Use current_user.id instead of #project.user_id. This way the new commit record would be created with currently logged in user's id instead of the user id of person who created the project.
I have two different controllers (scholarships_controller, scholarships_browse_controller) that look at the scholarship model. I want my Ransack search function to show the search results on the current page. So, for example, if I am on /scholarships_browse and I use the search functionality, I want it to use the scholarships_browse_controller and show the results on /scholarships_browse.
Currently, if I search on /scholarships_browse it uses the scholarships_controller and redirects to /scholarships to show the results (instead of /scholarships_browse).
Code for ScholarshipsBrowseController and ScholarshipsController
def index
#search = Scholarship.search(params[:q])
#scholarships = #search.result.page(params[:page]).per(3) #allows 3 scholarships on a page at a time
#search.build_condition
respond_to do |format|
format.html # index.html.erb
format.json { render json: #scholarships }
end
end
Code for scholarships browse index.html.erb:
<%= search_form_for #search do |f| %>
<%= f.condition_fields do |c| %>
<div class="field">
<%= c.attribute_fields do |a| %>
<%= a.attribute_select %>
<% end %>
<%= c.predicate_select compounds: false, only: [:cont, :eq, :gt, :lt] %>
<%= c.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
</div>
<% end %>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
So, I guess specifically I'm asking how do I make sure I am using the ScholarshipsBrowseController index instead of ScholarshipsController index when I am on /scholarships_browse ?
On your view:
<%= search_form_for #search, url: RAILS_ROUTEHERE do |f| %>
...
<%- end %>
search_form_for its an extension for form_for, so you can use the :url parameter to tell the form what should be the action of it (you can check the page source code when you render it on browser, you can check the tag <form action=""> to make sure it points to the right route.