Search form for Paper_trail history using Ransack gem - ruby-on-rails

I'm struggling to get a search form for my active record history.
I'm using the paper_trail gem as well as ransack. Both, alone, are working well. But whenever I try to implement a search form I get a strange error:
undefined method `paper_trail_versions_path' for #<#:0x007fede31da910>
This line from my views gets highlighted:
<%= search_form_for #q, html: {class: "input-group"} do |f| %>
Here's the code of the controller:
def history
#all_versions = PaperTrail::Version.order('created_at DESC')
#versions = #all_versions.paginate(:page => params[:page], :per_page => 100)
#q = #versions.search(params[:q])
#versions = #q.result
respond_to do |format|
format.html
end
end
the views:
<%= search_form_for #q, html: {class: "input-group"} do |f| %>
<%= f.search_field :whodunnit_or_item_id_cont, placeholder: "Search for Users or Actions..", class: "form-control" %>
<span class="input-group-btn">
<%= button_tag(type: 'submit', class: "btn btn-default") do %>
<i class="fa fa-search"></i>
<% end %>
</span>
<% end %>
Any Ideas?
Thanks in advance!
EDIT resolved, thanks to answer:
<%= search_form_for #q, html: {class: "input-group"}, :url => "/dashboards/history/" do |f| %>

The error your see comes from the URL the search_form_for helper tries to guess for your form's action.
Under the hood, Ransack uses the polymorphic_path rails helper, which is, according to the doc, a method
for smart resolution to a named route call when given an Active Record model instance
In your case, your model is a PaperTrail::Version, which resolves to paper_trail_versions_path.
To fix the error, you can either :
define the corresponding resource in your routes.rb file, so that the helper is defined
manually define the helper
provide to the search form a url option, with the path to your form's action.
Hope it helps!

Related

Rails form with url based on input

I feel like there's no easy way to do this in rails, but since I'm fairly noob in rails I decided to ask for solutions:
I have a form in a view that contains a single (text) input. How can I specify the form url such that it will do a GET to /something/<input> ?
I know I could:
use custom javascript code
post to an endpoint that would do the redirect
Is there any cleaner way?
(using rails 5.2.1 if relevant)
I think you could use something like this:
<%= form_tag(route_path method: :get) do %>
search <%= text_field_tag :search %>
<%= submit_tag 'Search' %>
<% end %>
It depends on which form helpers you use.
Maybe you can try this
In your form:
<%= form_with(url: "path_name/input_field_name", method: :get, local: true) do |f| %>
<%= f.text_field :input_field_name %>
<%= f.submit 'Search', input_field_name: nil %>
<% end %>
In your controller:
unless params[:input_field_name].blank?
#results = ModelName.where('input_field_name iLIKE ?', "%#{params[:input_field_name]}%")
end

Ransack Rails - One parameter in Array

I'm a total beginner in Rails and I try to use Ransack to filter results.
I have a model called 'adventures' which has many parameters, of which 'main_activity'. I try to implement a form in my homepage, where you can type the kind of activities you are looking for (later I will implement a dropdown so it will be limited to existing activities).
Here is what I have in my pages_controller:
def search
if params[:search].present? && params[:search].strip != ""
session[:bourse_aventuriers_search] = params[:search]
end
arrResult = Array.new
if session[:bourse_aventuriers_search] && session[:bourse_aventuriers_search] != ""
#adventures_main_activity = Adventure.where(active: true).all
else
#adventures_main_activity = Adventure.where(active: true).all
end
#search = #adventures_main_activity.ransack(params[:q])
#adventures = #search.result
#arrAdventures = #adventures.to_a
end
And in my home.html.erb
<%= form_tag search_path, method: :get do %>
<div class="row">
<div class="col-md-6">
<%= text_field_tag :search, params[:search], placeholder: "Quelle activité ?",
class:"form-control" %>
</div>
For the moment, whatever I type in the form, I get all the 'adventures' in the data base ; I find it logical because I did not change the 1st #adventures_main_activity = Adventure.where(active: true).all.
I don't know how to change it so that It will give me only the adventures whose main_activity is the keyword that I type in the form. Can anyone help me ? Thanks :)
I think you have a lot of surplus code in your search. Your controller should only need the #q parameter as follows:
#q = Adventure.ransack(params[:q])
#adventures = #q.result
The #adventures will then return any matches as an active record.
If you pass no parameters then the query will return all records (same as doing an Adventure.all).
When you submit the form the ransack search will pass a "q" param which will contain all the form items. Your's may look something like this:
"utf8"=>"✓", "q"=>{"search_cont"=>"rock climbing"}, "commit"=>"Search", "controller"=>"adventures", "action"=>"index"
If you use a debugger you can see this information by typing "params" in the command line. It will also appear in the server output.
Using an example of one I did in my application here is the exact code I used:
View:
<%= search_form_for #q do |f| %>
<div class="form-group col-sm-6">
<%= f.label :email_cont, "Email:" %>
<%= f.search_field :email_cont, :placeholder => "Please enter and email to search for", :class => "form-control" %>
</div>
<div class="form-group col-sm-3">
<%= f.submit 'Search', :class => 'btn btn-primary' %>
<%= link_to 'Reset', users_path, :class => 'btn btn-default' %>
</div>
<% end %>
Controller
def index
#q = User.ransack(params[:q])
#users = #q.result(distinct: true).order(:email).page params[:page]
end
The classes are just Bootstrap CSS which you won't need if you are not using bootstrap.
EDIT
The search_form_for #q has to exactly that and the #q has to be set in the params for it to work. Ransack is very specific about them. So your #search in
#search = #adventures_main_activity.ransack(params[:q])
should be #q. In your view change your form_tag to search_form_for and it should work. Good luck.

How do I pass a parameter to a form partial that is shown via CSS?

So my form partial is loaded in my div id="secondary", which is hidden on first page load.
When the user hits a button with a class called toggleSidebar, then the _form.html.erb is shown.
I have overridden the partial to display a new form (even if update is pressed) when a user is not logged in like this:
<%= simple_form_for(Post.new, html: {class: 'form-horizontal' }) do |f| %>
As opposed to the regular version that looks like this, and is included in an if statement on this same partial:
<% if current_user and current_user.has_any_role? :editor, :admin %>
<%= simple_form_for(#post, html: {class: 'form-horizontal' }) do |f| %>
The real issue is in my view, when someone goes to Update, this is what happens when the user is logged out:
<%= link_to "Update", "#", class: "togglesidebar" %>
This is perfect, it executes the CSS and shows the empty form partial perfectly.
However, when a user is logged in, I want it to send the parameter parent_id: #post with the execution of the sidebar being toggled.
This is how it looks with a normal new_post_path view (i.e. the non-sidebar new post view):
<% if current_user %>
<%= link_to "Update", new_post_path(parent_id: #post) %>
<% end %>
This is what my PostController#New looks like:
def new
#post = Post.new(parent_id: params[:parent_id])
end
How do I either pass the params in the regular non new_post_path version, or tackle this another way?
You could probably use a helper method.
Just browse to the 'helper' directory under 'app' folder and create a file similar to [name]_helper.rb
In this file create a module by [name]Helper and declare your helper method in this module.
This module is automatically required by rails.
A small example might help you.
The code in the link_helper.rb under app/helper directory
module LinkHelper
def populate_link(link1, link2, parameter)
if current_user
public_send(link2, parameter)
else
link1
end
end
end
The code in views is
<%= link_to 'update', populate_link('#', 'new_requirement_path',parameter: 33) %>
I'm a bit confused by the question, but I think you may be just need to use a hidden field to pass the parent_id param back?
e.g./
<%= simple_form_for(Post.new, html: {class: 'form-horizontal' }) do |f| %>
<%= f.hidden_field :parent_id, { value: #post.try(:id) } %>
<% end %>
HTH?
I am also a bit confused, but the following railscast might help you. It shows how to embed data in an html-tag. You can probably do it the same way.
railscast-> passing data to javascript
Out of the possibilities there I'd recommend the data-attribute:
<%= simple_form_for,(Post.new, html: {class: 'form-horizontal' }, **data: {post_id: #post.id}**) do |f| %>
<% end %>

What are the differences between form_for #project_profile and form_for :project_profile

I just started to learn rails. My rails version is 3.0.7. I am wondering what are the differences between <% form_for :project_profile %> and <% form_for #project_profile %>. I have this question because I went into the following situation:
If I use <% form_for :project_profile %>, it doesn't give me an error, but the form is actually not working.
If I use <% form_for #project_profile %>, I will get an error: undefined method `project_profile_path' for #<#:0x00000103546d80>
If I use <%= form_for #project_profile, :url => "/projects/#{params[:project_id]}/profile/update" do |f| %>, it will work but the code is ugly.
You can refer to the following codes to understand the context of my problem better.
I have a project model and a project_profile model. One project has one project_profile.
The following two lines are from my routes.rb.
match '/projects/:project_id/profile/edit' => "project_profiles#edit"
match '/projects/:project_id/profile/update' => "project_profiles#update"
This is from my project_profiles_controller.rb
class ProjectProfilesController < ApplicationController
def edit
#project_profile = Project.find(params[:project_id]).project_profile
end
def update
#project_profile = Project.find(params[:project_id]).project_profile
respond_to do |format|
if #project_profile.update_attributes(params[:project_profile])
format.html {}
else
format.html { render :action => "edit" }
end
end
end
end
The following code is from _form.html.erb
<%= form_for #project_profile, :url => "/projects/#{params[:project_id]}/profile/update" do |f| %>
<div class="field">
<%= f.label :title %>
<br/>
<%= f.text_field :title %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You should learn about resource and nested resource routing in Rails.
The way you define controller is also not conventional. There is an article on Rails Guides on Getting Started section that covers that too.
Basically spoken, form_for #project_profile is an advanced (resource-oriented), nowadays preferred style. If you want to dig a little deeper into this, the API itself explains the difference pretty well.
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for
cheers

Rails: Using form (collection select) to call show-action

A model named 'book' with attributes 'name' and 'id' is given. How can i use this collection select to call the show-action of a certain book? The one code mentioned below returns the following error message:
Couldn't find Book with ID=book_id
<% form_tag(book_path(:book_id)), :method => :get do %>
<p>
<%= label(:book, :id, 'Show Book:') %>
<%= #books = Books.find(:all, :order => :name)
collection_select(:book, :id, #books, :id, :name)
%>
</p>
<p>
<%= submit_tag 'Go' %>
</p>
<% end %>
book_path is generated once only, for the form tag itself. It won't be updated whenever your selection changes.
When you submit that form, it's going to request the following URL:
/books/book_id?book[id]=5
Since your book_path thinks book_id is the ID number you wanted, it tries to look that up. You could do what you want you by changing the code in your controller from:
#book = Book.find(params[:id])
to:
#book = Book.find(params[:book][:id])
But it kind of smells bad so be warned.
You can create a new route that is not based on the id, like
get 'books/show' # put this above your "resources :books"
and change your form to
<% form_tag books_show_path, :method => :get %>

Resources