I have a controller that manages a list of Post and I added filter in it. The posts have rating system (0-5 rating). The filter lets user input what rating they want to see, and it will display inputted rating and higher.
For example, I have 10 posts, and 7 of them has rating of 3.5 and higher. If user inputs 3.5 in the rating filter, it will only displays 7 posts with the corresponding rating.
Here is the code:
index.html.erb
...
<%= form_tag posts_path, method: :get, class: "form-inline" do %> <!-- form_tag on posts path (index), use get method since we are displaying results and not altering/ submitting new data -->
<div class="rating form-group">
<%= label_tag :rating %>
<%= number_field_tag :rating, params[:rating], step: 0.5, min: 0, max: 5, class: "form-control" %>
<%= submit_tag "Search", name: nil, class: "btn btn-primary"%>
</div>
<% end %>
...
Here is my index:
def index
#posts = Post.all
#posts = Post.where("rating >= ?", params["rating"]) if params["rating"].present?
end
My problem is, I want to give users the ease of removing the filter whenever they do page refresh. How can I remove the filter every time user refreshes the page so that it displays all 10 posts again? Right now, if I want to display all 10 posts again after making the filter, I either have to go to the field box and delete the number 3.5 I inputted earlier and resubmit the form, or I have to change the url manually from
http://localhost:3000/posts?utf8...&rating=3 to http://localhost:3000/posts; I think it would be more convenient for users to just refresh the page.
I guess I can rephrase it as, how can I change my controller from #posts = Post.where... to #posts = Post.all again when user refreshes page?
I don't know what you routes are, but lets assume your posts_path is posts/index and routes to the index method in the PostsController.
First, I would change your routes config so that post/index will be matched to the index method in the PostsController for both :get and :post requests:
# config/routes.rb
match 'posts/index' => 'posts#index', as: 'posts', via: [:get, :post]
Next, I would change your form to use the :post method instead of :get:
<%= form_tag posts_path, method: :post, class: "form-inline" do %>
<div class="rating form-group">
<%= label_tag :rating %>
<%= number_field_tag :rating, params[:rating],
step: 0.5, min: 0, max: 5, class: "form-control" %>
<%= submit_tag "Search", name: nil, class: "btn btn-primary"%>
</div>
<% end %>
Finally, I would change the where clause your controller to accept params[:rating] if provided, but default to 0 if params[:rating] is nil:
def index
#posts = Post.where("rating >= ?", params[:rating]||=0)
end
This is of course assuming that you do not have negatively rated posts...if you do, you can default to a sufficiently negative number (that all posts are rated higher than).
Now, when the user submits the form, the url will no longer haveparams[:rating] in the query string.
Hope this helps!
The issue here is your query string stays when you refresh the page.
So one way to do it is to replace the url and remove the query string. With the history APi in modern browsers, you can do this.
history.replaceState({}, 'some title', '/');
You can simply plug this into your document / head ready callback. So after your user gets the response with ratings, you change the url back to the one without query string. So when it gets refreshed, it makes request to your server without the rating query string.
But keep in mind, your user won't be able to bookmark your page based of the ratings. If you want to do that, you will need to switch your get requst to post request. Check this wiki page out for more info.
https://en.wikipedia.org/wiki/Post/Redirect/Get
Related
Situation:
An order is created by ordercontroller create method into a orders table.
Then a video is uploaded by videoordercontroller create method into the videoorder table associated with the order_id.
I have this in the orders show page to upload the video to the order:
<%= form_for([#order, #video_order]) do |form| %>
<%= form.file_field :video %>
<%= form.submit "Upload", class: "btn btn-success" %>
This form technically disapears after submission but i am testing updating the video because i also want to give the ability to update the video in case a wrong video is uploaded.
I tried:
<%= form_for([#order, #video_order], :url => edit_order_video_order_path(#order.id, #video_order), remote: true ) do |form| %>
<%= form.file_field :video %>
<%= form.submit "Upload", class: "btn btn-success" %>
But this gives me the
"(No route matches [POST] "/orders/150/video_orders/150/edit")"
Which, of course this wouldn't work but i also can't figure out how to allow to update the video tables order_id from the same URL page. I don't want to send the user to a new page for convenience.
So basically, how can i allow updating the orders video in the video table?
Here's the models:
video_order model
belongs_to :order
validates :order_id, uniqueness: true
order order model
has_one :video_order
The video_order model has the order_id and video only.
the order model doesn't have a video_id column.
Also, if you see any associations being wrong or have better ways, feel free to let me know.
Rake:
edit_order_video_order GET /orders/:order_id/video_orders/:id/edit(.:format) video_orders#edit
PATCH /orders/:order_id/video_orders/:id(.:format) video_orders#update
PUT /orders/:order_id/video_orders/:id(.:format) video_orders#update
This is taking place in the Order show page
I have this method in the order controller:
def show
#user = current_user
#video_order = VideoOrder.new
end
This where the uploading of the video takes place. i also want to allow updating from it with a seprate form
form_for method has a options parameter, you can set the form method as 'patch' as follows:
form_for #object, url: 'some_url', method: 'patch'
Looks like this works for updating the table and not creating a new row:
<%= form_for(#order.video_order) do |form| %>
Only issue I'm currently having is the redirect after. I get "Cannot redirect to nil!" but i will figure that out soon enough.
Redirect needed to be along the lines of this:
redirect_to order_path(#video_order.order_id)
In orde to redirect back to the order show page
This solution ended up being so simple! :)
I have a search form and I need a checkbox that will select and then return whether a particular listing allows pets. I have created a custom route, controller method, and erb in the view. However, I am not accomplishing what I set out to do.
When a user clicks the Pets Allowed checkbox and then clicks search, the listings where pets allowed == true should be returned. I am not sure how to go about that.
This is the current code, but does not accomplish what I am after. This will redirect to /pets_allowed but that isn't a real thing.
listings_controller:
def pets_allowed
#listings = Listing.where(pets: true)
end
routes.rb:
get "pets_allowed" => "listings#pets_allowed"
html.erb:
<div>
<%= link_to 'Pets Allowed', pets_allowed_path, :class => 'button btn-transparent' %>
</div>
You probably need to use form_for instead of link_to.
<%= form_for :search_pets, url: pets_allowed_path, method: :get do |f| %>
<%= f.check_box :has_pets %>
<% end %>
Now in action,
def pets_allowed
#listings = Listing.where(pets: params[:search_pets][:has_pets])
end
When the checkbox is unchecked, it will return all the listings with no pets and when its checked it will return all the listings that have pets.
Hope that helps!
I am working on a rails web app which manages students and courses. I have a courses controller which has the following index action:
def index
#courses = Course.paginate(:page => params[:page], :per_page => 1)
#courses.order(:startDate)
##thisCourse = Course.find(params[:page])
end
So pretty standard except for one thing - all the details of a single course are shown on one page and to show the details of the next course, you move to the next page of the pagination.
The problem is that in this index page showing the details of 1 course per pagination, I have a "Sign Up!" button which when pressed needs to create a a new record in the 'signups' db table which has the automated 'id' field and then the 'user_id' and the 'course_id' fields.
The 'user_id' is easy to find (current_user.id).
The 'course_id' is proving difficult. I imagine that pressing the Signup button should send the course_id to the signups_controller where a create function can do the work. But how can I get this exact course ID from the index page to the signups_controller's create action?
As you can see in the code I pasted from the courses_controller's index action,the '#thisCourse' variable has been commented out because I have found no way to define which course is currently being shown on the page.
The fields are rendered by the will_paginate Gem so I'm not sure how it's generating the fields but I was thinking that maybe I could create a named hidden field which includes the course_id and use that when the sign up button is pressed, however I'm not sure how to go about it.
Does anybody have any ideas?
Thanks!
Well, you can use show method (output one course) instead of index(output all courses) method, that will always get your course id through params.
Basically I changed my approach to the problem. I removed the button which was supposed to call the signups_controller and create the new record in the signups table. This button was replaced by adjusting the form_for helper so that it's submit button would send all the necessary data to the signups_controller (including the id value which was added to the form as a hidden field).
The form ended up looking like this:
<%= form_for course, :url => {:controller => "signups", :action => "create"}, :method => "post" do |f| %>
<%= hidden_field_tag :course_id, course.id %>
<%= f.label :"Course Title" %>
<%= f.text_field :courseTitle, class: 'form-control' %>
+ all fields included in the form....
<%= f.submit "Sign Up!", class: "btn btn-primary" %>
<% end %>
This parameter of form_for defines which controller and which action in that controller is the submission target:
:url => {:controller => "signups", :action => "create"}
and this parameter overwrites the default http action (default is PATCH but in this case I wanted to POST i.e. create a new entry in the signups table):
:method => "post"
I'm not sure if this is a very quick and dirty solution but technically it gets the necessary data to the correct destination controller.
I have an Article resource and have defined resourceful routes for it. I want to create a simple page that shows the articles of the current user. I am aware that it is possible to do so by adding another action, for example 'search' to articles controller which will contain the custom code that searches for articles that have the same user id. And for the routes:
resources :articles do
get 'search'
end
But I'm not sure if adding a custom action is a good idea in this case. I'm thinking I can still use the index action (which shows all articles) and pass some sort of parameter from the url so that it can distinguish if the user wants to see all articles or just his own. But I'm not sure exactly how this can be done. Any help would be great. Thanks!
You can use the query string to pass parameters. see here
So you can pass something like .../articles?user_id=2
In your controller, just change the behavior according to the user_id parameter.
you don't need to create a new action/view for it.
You can add a small form to filter all articles or only my articles, for example:
<%= form_tag articles_path, method: :get do %>
<%= radio_button_tag :search, "all", :checked => true %>
<%= label_tag :all %><br />
<%= radio_button_tag :search, "my" %>
<%= label_tag :my_articles %><br />
<%= submit_tag "filter", name: nil %>
<% end %>
than in your controller:
def index
if params[:search] == 'my'
#articles = current_user.articles
else
#articles = Article.all
end
In the application there is a default report the user see's listing all the calls for a certain phone. However, the user can select a date range to sort the list from. Doing that, everything works correctly, but when the user selects the date range and changes to the second page, the date-range is lost and it goes back to the default view for the second page.
In my controller, I'm checking to see if the date_range param is being passed in. If it isn't, I display the entire listing, if it is, I display the records in between the certain date range.
The problem is, when I click on a new page, the new parameter doesn't include the old date-range that it should.
How do I go about doing this, I was thinking of doing some class level variable test but that isn't working out the way I thought. And I'm pretty stuck.
I don't have the code right in front of me, but if I remember correctly it's something like this:
<% form for :date_range do |f| %>
<%= f.calendar_date_select :start %>
<%= f.calendar_date_select :end %>
<%= f.Submit %>
<% end %>
And in the controller, it's something like:
if params[:date_range] == nil
find the complete listings without a date range
else
find the listings that are within the date range
end
The main problem is that you're using a POST request when submitting the form, but will-paginate uses a GET request. You should also use form_tag instead of form_for because form_for will nest the fields in a hash which is not possible with GET.
<% form_tag items_path, :method => 'get' do %>
<%= calendar_date_select_tag :start_date %>
<%= calendar_date_select_tag :end_date %>
<%= submit_tag "Submit", :name => nil %>
<% end %>
Then check params[:start_date] and params[:end_date] directly. You'll need to change items_path to whatever page you want the form to go to.
This is untested but it should get you in the right direction.
You could modify the link_to (assuming that's how you go through pages) so that it passed the date_range param.
= link_to 'Next', #whatever_path, :date_range => #date_range
where #date_range could be set in your controller by capturing your params in an instance variable.. .
But there may be a better solution.