I've got a simple search form, in rails 4 app, that needs two params passed to be able to show relevant data.
I'm getting an 'Mysql2::Error: Unknown column 'data inputted' but the columns do exist. If I instead of '#search = Page.where(params[:one] && params[:two])' use '#search = Page.all' the data shows, but all of it shows.
Form
<%= form_tag(page_show_path, id: "search-form") do %>
<%= text_field_tag :one, params[:one], placeholder: "One" %>
<%= text_field_tag :two, params[:two], placeholder: "Two" %>
<%= submit_tag "Search", :name => nil %>
<% end %>
Model
def self.one(query)
where("one = ?", "%#{query}%")
end
def self.two(query)
where("two = ?", "%#{query}%")
end
Controller
def show
if (params[:one] && params[:two]).present?
#search = Page.where(params[:one] && params[:two])
else
redirect_to page_path, notice: "Not a valid combination"
end
end
You can Create and Use Scope.
scope :find_one_two, ->(query_one, query_two) { where("one = ? AND two = ? ", query_one, query_two) }
#search = Page.find_one_two(params[:one], params[:two])
OR
You can use.
#search = Page.where("one = ? AND two = ?", params[:one], params[:two])
def show
if (params[:one] && params[:two]).present?
#search = Page.where("one like ? AND two like ? ", "%#{params[:one]}%", "%#{params[:two]}%")
else
redirect_to page_path, notice: "Not a valid combination"
end
end
This may solve your problem.
Related
I am trying to filter the index page of a todo list, I have column t.datetime "completed_at" in my tasks table.
Currently my form looks like this,
<%= form_with model: #task, method: :GET do |f| %>
<%= f.label "Complete" %>
<%= f.radio_button :completed, "complete" %>
<%= f.label "Incompleted" %>
<%= f.radio_button :completed, "incomplete" %>
<%= f.label "All tasks" %>
<%= f.radio_button :completed, "all_tasks" %>
<%= f.submit "Filter" %>
<% end %>
and my controller
def index
if params[:completed] == "complete"
#tasks = Task.where(completed_at: !nil)
elsif params[:completed] == "incomplete"
#tasks = Task.where(completed_at: nil)
else
#tasks = Task.all
end
end
I am trying to use completed_at equalling nil to be an incomplete task, and complete tasks will be !nil as a datetime will be stored when checked as complete. If anyone could point me in the right direction or give an example of how to get this working I'd appreciate it. Thanks.
rails - 6
ruby - 2.7
By negating nil you'll get true, so that won't filter tasks with not nil completed_at rows, but tasks with completed_at as true.
You could assign #tasks to Task.all, and then depending on the value of params[:completed] modify it:
def index
completed = params[:completed]
#tasks = Task.all
#tasks = Task.where.not(completed_at: nil) if completed == 'complete'
#tasks = Task.where(completed_at: nil) if completed == 'incomplete'
end
where.not does the trick to perform an IS NOT NULL query.
Or if you want to be more object-oriented;
class Tasks
def initialize(completed)
#completed = completed
end
def complete_filter
return Task.where.not(completed_at: nil) if complete?
return Task.where(completed_at: nil) incomplete?
Task.all
end
private
attr_reader :completed
def complete?
completed == 'complete'
end
def incomplete?
completed == 'incomplete'
end
end
def index
#tasks = Tasks.new(params[:completed]).complete_filter
end
I try to pass 2 options for search. First [:q] for input text by visitor and another one from model camping "nomdep" (like departement in english). When i try to search by input it's works, but since i try to add select_tag i have an error
ERROR
undefined method `map' for nil:NilClass
I m lost, do u have any ideas ?
Sorry for my english, i m french.
Home_controler.rb
def index
if params[:q].nil?
"Entrez un mot clef"
else
#campings = Camping.__elasticsearch__.search params[:q,:nomdep]
#camping = Camping.all
end
end
def result
if params[:q].nil?
#campings = []
else
#campings = Camping.__elasticsearch__.search(params[:q]).page(params[:page]).per(14).results
end
end
View
<div class="search">
<%= form_tag(result_path, method: :get) %>
<%= text_field_tag :q, params[:q], class:"search-query form-control" %>
<%= select_tag(:nomdep, options_for_select(#camping)) %>
<%= submit_tag "Partez", class:"btn btn-danger", name: nil %>
</div>
EDIT
Now i dont have any error but the search dont work if [:q] empty. So if i only select_tag => no result.
How fix this ?
My full home_controller.rb
class HomeController < ApplicationController
def index
#camping = Camping.all
if params[:q].nil?
"Entrez un mot clef"
else
#campings = Camping.__elasticsearch__.search params[:q, :nomdep]
end
end
def result
if params[:q].nil?
#campings = []
else
#campings = Camping.__elasticsearch__.search(params[:q]).page(params[:page]).per(14).results
end
end
end
my view
<div class="search">
<%= form_tag(result_path, method: :get) %>
<%= select_tag :nomdep, options_from_collection_for_select(#camping, :id, :nomdep), prompt: "Département" %>
<%= text_field_tag :q, params[:q], class:"search-query form-control" %>
<%= submit_tag "Partez", class:"btn btn-danger", name: nil %>
</div>
#camping = Camping.all
This variable will be nil unless :q was passed in params to index action. options_for_select(#camping) will attempt to call #map on this variable and raise error when it is not initialized.
You should make sure it is initialized. For example, try rewriting your action:
def index
#camping = Camping.all
if params[:q].nil?
"Entrez un mot clef"
else
#campings = Camping.__elasticsearch__.search params[:q]
end
end
I want to say a big big big THANKS to #Baradzed ! We talked yesterday and he find a solution thats work perfectly !
home_controller.rb
class HomeController < ApplicationController
def index
#camping = Departement.all
if params[:q].blank? || params[:nomdep].blank?
#campings = Camping.__elasticsearch__.search params[:nomdep]
else
#campings = Camping.__elasticsearch__.search params[:q]
end
end
def result
querystring = params.slice(:nomdep, :other_param, :any_params_except_q_because_we_will_process_q_separately)
.select{|k,v| v.present?}
.map {|key, value| "#{key}:\"#{value.gsub(/([#{Regexp.escape('\\+-&|!(){}[]^~*?:/')}])/, '\\\\\1') }\""}
.join(" AND ")
freetext = params[:q]
freetext.gsub!(/([#{Regexp.escape('\\+-&|!(){}[]^~*?:/')}])/, '\\\\\1')
querystring = ["*#{freetext}*",querystring].select{|v| v.present?}.join(" AND ") if params[:q].present?
if querystring.blank?
flash[:notice] = "Aucune mots clefs"
redirect_to action: :index and return
else
#campings = Camping.__elasticsearch__.search(
query: { query_string: {
query: querystring
}}).page(params[:page]).per(14).results
end
#hash = Gmaps4rails.build_markers(#campings) do |camping, marker|
marker.lat camping.latitude
marker.lng camping.longitude
marker.infowindow render_to_string(:partial => "/campings/infowindow", :locals => { :camping => camping})
marker.picture ({
"url" => "http://avantjetaisriche.com/map-pin.png",
"width" => 29,
"height" => 32})
end
end
end
view
<div class="search">
<%= form_tag(result_path, method: :get) %>
<%= select_tag :nomdep, options_from_collection_for_select(#camping, :nomdep, :nomdep), prompt: "Département" %>
<%= text_field_tag :q, params[:q], class:"search-query form-control" %>
<%= submit_tag "Partez", class:"btn btn-danger", name: nil %>
I get this error and for the life of me I can't figure out why. Help would be appreciated. :
error 3: error displayed after changes
error 4: after User.all.each do |user|
Error: Undefined method 'each' for nil: nilClass
my ruby/haml code is as follows
viewer code:
-# This file is app/views/projects/index.html.haml
%h1 All Project Tasks
= form_tag projects_path, :method => :get do
Include:
- #all_users.each do |user|
= user
= check_box_tag "users[#{user}]", 1, ("checked" if #filtered_users.find_index(user))
= submit_tag 'Refresh', :id => "users_submit"
%table#projects
%thead
%tr
%th{:class => ("hilite" if params[:sort] == "title")}= link_to "Title", {:controller => "projects", :sort => "title", :filter => #filtered_users.to_s}, :id => "title_header"
%th Task Details
%th Assigned Usertimot
%th{:class => ("hilite" if params[:sort] == "due_date")}= link_to "Due Date", {:controller => "projects", :sort => "due_date", :filter => #filtered_users.to_s}, :id => "due_date_header"
%tbody
- #projects.each do |project|
%tr
%td= project.title
%td= link_to "More about #{project.title}", project_path(project)
%td= project.user
%td= project.due_date.to_formatted_s(:long)
= link_to 'Add new project task', new_project_path
controller code:
class ProjectsController < ApplicationController
def show
id = params[:id] # retrieve project task ID from URI route
#project = Project.find(id) # look up project task by unique ID
# will render app/views/projects/show.<extension> by default
def index
#projects_users = Project.all_users
# remembered settings
if (params[:filter] == nil and params[:users] == nil and params[:sort] == nil and
(session[:filter] != nil or session[:users] != nil or session[:sort] != nil))
if (params[:filter] == nil and session[:filter] != nil)
params[:filter] = session[:filter]
end
if (params[:sort] == nil and session[:sort] != nil)
params[:sort] = session[:sort]
end
redirect_to projects_path(:filter => params[:filter], :sort => params[:sort], :users => params[:users])
else
if (params[:filter] != nil and params[:filter] != "[]")
#filtered_users = params[:filter].scan(/[\w-]+/)
session[:filter] = params[:filter]
else
#filtered_users = params[:users] ? params[:users].keys : []
session[:filter] = params[:users] ? params[:users].keys.to_s : nil
end
end
session[:sort] = params[:sort]
session[:users] = params[:users]
if (params[:sort] == "title")
if ( params[:users]or params[:filter] )
#projects = Project.find(:all, :order => "title")
end
end
if (params[:sort] == "due_date")
if ( params[:users]or params[:filter] )
#projects = Project.find(:all, :order => "due_date")
end
if (params[:sort] == nill)
if(params[:users] or params[:filter])
#projects = Project.all
end
end
end
end
def new
# default: render 'new' template
end
def create
#project = Project.create!(project_params)
flash[:notice] = "#{#project.title} was successfully created."
redirect_to projects_path
end
def edit
#project = Project.find params[:id]
end
def update
#project = Project.find params[:id]
#project.update_attributes!(project_params)
flash[:notice] = "#{#project.title} was successfully updated."
redirect_to project_path(#project)
end
def destroy
#project = Project.find(params[:id])
#project.destroy
flash[:notice] = "Project '#{#project.title}' deleted."
redirect_to projects_path
end
private
def project_params
params.require(:project).permit(:title, :description, :extended_description, :user, :due_date)
end
end
end
i understand that the spacing for haml may be a little off, just the nature of trying to format the code block thanks in advance!
viewer code:
class Project < ActiveRecord::Base
def self.all_users
allUsers = []
Project.all.each do |project|
if (allUsers.find_index(project.user) == nil)
allUsers.push(project.user)
end
end
return allUsers
end
end
You are probably getting the error on this line in your view:
#all_users.each do |user|
The reason for the error as I see it is that you don't have #all_users instantiated anywhere in your controller's index action method.
First switch #all_users to #projects_users. Also it appears that your all_users method in project.rb is overly complex and is returning nil. Try modifying project.rb to the following:
class Project < ActiveRecord::Base
def self.all_users
all.includes(:user).map(&:user).uniq
end
end
Undefined method 'each' for nil: nilClass
This error basically means you don't have any data in your variable.
In other languages, it would mean you've not delcared the variable. Because Ruby is object orientated, it will populate the variable with the nilClass class.
Many new Ruby devs are thrown by the "undefined method" exception message; it's the nilClass you have to look out for.
--
To explain the error properly, because Ruby is object orientated, every variable is actually a data object, represented by a class. In Rails, you can define these classes as models (User.find etc).
Unlike other languages, Ruby treats these objects as is -- it uses methods on them. Other languages fit data into functions, E.G PHP's each function:
#PHP
<$ each($people) $>
#Ruby
<% #people.each do |person| %>
Thus, the "no method" error basically means that Ruby cannot find the method you're calling on the nilClass. It throws developers because they think that "I have the x method on the User class", not realizing that the variable has been populated by the nilClass instead.
The short of it is that you have to either make your calls conditional, or populate the variable properly.
The error appears to be here:
#app/views/project/index.html.haml
#all_users.each do |user|
#app/controllers/projects_controller.rb
class ProjectsController < ApplicationController
def index
#projects_users = Project.all_users
end
end
You're not assigning #all_users at all
You're using an inefficient way to get "all users"
Here's what I'd do:
#app/controllers/projects_controller.rb
class ProjectsController < ApplicationController
def index
#users = Project.all_users
end
end
#app/models/project.rb
class Project < ActiveRecord::Base
scope :all_users, -> { joins(:users) } #-> this needs to be tested
end
#app/views/projects/index.haml
- #users.each do |user|
= user.name
I am pretty inexperienced with pure SQL, you'll be best referring to the joins documentation for a clearer perspective.
I want to pass the value of a form to a Controller that should call a method from the Model for searching products.
I want to pass the category_id and the string that the user writes at the textfield.
I would pass to the model even the blank value of params (if the user doesn't write something on the search bar or choose none category)
I want to save even the blank value cause in the model, the SQL blank variable take "all" things.
And this is good a cause if there is something in the params , the SQL will find that thing, BUT if there is nothing in the params, the SQL will take all products.
I'm not able to save the value of params in varibiles cause if params is blank it returns to me this error:
undefined method `[]' for nil:NilClass
I hope you understand me and what I want to do.
In other words , I want to use a simple assignment to pass a value (even blank values) to a model to do a SQL query. In one shoot of code I want to program two cases.
Here my code.
In my Controller:
...
if params[:search]
#search_name = params[:search]
end
if params[:category][:name]
#category = params[:category][:name]
end
#products = Product.search(#search_name,#category)
...
In my Model:
def self.search(search_name,category)
ricerca = Product.where("category_id = ? ",category)
ricerca = ricerca.where("title like ? ", "%#{search_name}%")
end
You can get category parameters by defining a method like,
def category_params
params.fetch(:category, {})
end
And, then look up for Products by,
#search_name = params[:search]
#category = category_params[:name]
#products = Product.search(#search_name, #category)
In my opinion, if you are making a direct query on Product, then you should do like,
def product_params
params.fetch(:product, {})
end
#category = product_params[:category_id]
#title = product_params[:title]
#products = Product.search(#category, #title)
And in product model,
def self.search(category, title)
where("category_id = ? AND title LIKE ?", category, "%#{title}%")
end
Try this:
#search_name = params[:search]
#category = (params[:category].blank? ? nil : params[:category][:name])
#products = Product.search(#search_name,#category)
#Vito, change the line -> #category = params[:category][:name] in your controller by
#category = params[:category].present? ? params[:category][:name]
the issue is when you don't select the category then params[:category] comes nil and you are fetching name from params[:category] that's why error "undefined method `[]' for nil:NilClass" is comming.
Hope this will resolve your problem.
i still have problems , cause when i wrote
if params[:category]
#category = params[:category][:name]
else
#category = " "
end
if params[:search]
#nome_ricerca = params[:search]
else
#nome_ricerca = " "
end
#products = Product.search(#nome_ricerca,#category)
i have this problem:
Showing C:/Bitnami/depot/app/views/store/index.html.erb where line #18 raised:
undefined method `name' for "":String
Extracted source (around line #18):
<p>
<%= label_tag :search, 'Search:' %>
<%= text_field_tag :search, params[:search] %>
<%= collection_select :category, :name, Category.all, :id, :name, {:prompt => 'All Categories'} %>
<%= submit_tag "Search", name: nil %>
</p>
what is this?
Ok, i fixed the problem
it was (i think) concerning the fact that i used #category as variable name
maybe the view gets in confusion for this
i call #category in #cat and the problem disappears
But , now the problem is that the SQL query doesn't return all the category if i pass "" in the variable #cat
How can i have all the result of a query? with like %% it works but with
category_id = "" no. why?
I post the code fixed for others:
In Controller:
if params[:category]
#cat = params[:category][:name]
else
#cat = ''
end
if params[:search]
#nome_ricerca = params[:search]
else
#nome_ricerca = ''
end
#products = Product.search(#nome_ricerca,#cat)
In model:
def self.search(nome_ricerca,categoria)
ricerca = Product.where("title like ? AND category_id = ? ", "%#{nome_ricerca}%",categoria)
end
LAST POST:
PROBLEM FIXED:
In Controller
#stringa_sql = ""
if params[:search]
#nome_ricerca = params[:search]
else
#nome_ricerca = ''
end
#stringa_sql = "title like "+"'%"+#nome_ricerca+"%'"
if params[:category]
if params[:category][:name] != ""
#cat = params[:category][:name]
#stringa_sql += " AND category_id = "+#cat
else
#cat = ''
end
end
#products = Product.search(#stringa_sql)
In Model:
def self.search(stringa_sql)
ricerca = Product.where(stringa_sql)
end
Question: does this solution suffer Sql Injection ?
Thx all :)
I Hope this solution will help someone.
I've build quite complex form which creates one prescription with many realtions. I am using this syntax in view:
- provide(:title, 'Create prescription')
%h1 Add medicines to prescription
.row
.span6.offset3
= form_for #prescription do |f|
= render 'shared/error_prescription_messages'
%p
= f.hidden_field :patient_id, :value => params[:patient_id]
= f.hidden_field :user_id, :value => current_user.id
= f.fields_for :relations do |builder|
= render 'child_form', :f => builder
%p= f.submit "Submit"
chlid_form is quite simple :
- it=f.options[:child_index].to_i
- n= it.to_s
%h2
= "Medicine ##{it+1}"
= f.hidden_field :medicine_id, :id => "my_medicine_id#{it}"
- if params[:prescription].nil? || params[:prescription][:relations_attributes][n.to_sym][:medicine_name].nil?
= f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path, :id_element => "#my_medicine_id#{it}"
- else
= f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path, :id_element => "#my_medicine_id#{it}", :value => params[:prescription][:relations_attributes][n.to_sym][:medicine_name]
= f.label :amount, "Amount of medicine boxes"
= f.number_field :amount, :value => 1
= f.label :daily
= f.number_field :daily, :value => 1
= f.label :period_in_days, "Duration of treatment (in days)"
= f.number_field :period_in_days, :value => 1
So as you can see I'm using f.options[:child_index] to get index of child (0,1,2...) cause I generate multiple items with this particular form. I then put it to variable it and sucessfully use it in :id_element => "#my_medicine_id#{it}" which works PERFECTLY fine (creates my_medicine_id0, my_medicine_id1 ....) Although it doesn't work in this line:
:value => params[:prescription][:relations_attributes][n.to_sym][:medicine_name]
where n is just n=it.to_s.
I though somethings wrong in controller but if I change this line to whatever
:value => params[:prescription][:relations_attributes]**[:'0']**[:medicine_name] or any other integer from 0 to 4 everything works great, but I NEED dynamic change in this one. So I got proof that it DOES work because it generates integer fine here "#my_medicine_id#{it}" but won't work in hash! And when I print the whole hash from params I get this:
{"patient_id"=>"7", "user_id"=>"1", "relations_attributes"=>{"0"=>{"medicine_id"=>"13490", "medicine_name"=>"Locacid 500 mcg/g (0,05%) (1 tuba 30 g)", "amount"=>"0", "daily"=>"1", "period_in_days"=>"1"}, "1"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "2"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "3"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "4"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}}}
so to get the values I need it's pretty obvious that
params[:prescription][:relations_attributes][SOME_KIND_OF_INETEGER][:medicine_name] should work, but doesn't.
Controller code:
class PrescriptionsController < ApplicationController
before_action :signed_in_user
before_action :doctor_user, only: [:new, :create]
before_action :pharmacist_user, only: [:update]
def new
#prescription =Prescription.new
5.times { #prescription.relations.build }
end
def create
#prescription = Prescription.new(new_prescription_params)
if #prescription.save
flash[:success] = "Prescription created."
redirect_to #prescription
else
5.times { #prescription.relations.build }
render 'new', :prescription => params[:prescription]
end
end
def show
#prescription = Prescription.find(params[:id])
#medicines = #prescription.medicines.paginate(page: params[:page], :per_page => 10)
end
def update
#prescription = Prescription.find(params[:id])
#patient = Patient.find(params[:patient_id])
if !prescription_expired?(#prescription)
#prescription.realized = 1
if #prescription.save
flash[:success] = "Prescription realized."
redirect_to #patient
else
redirect_to root_url
end
else
flash[:notice] = "Can't realize, prescription expired."
redirect_to #patient
end
end
private
def new_prescription_params
params.require(:prescription).
permit(:patient_id, :user_id, relations_attributes: [:medicine_id, :medicine_name, :amount, :daily, :period_in_days])
end
def doctor_user
redirect_to(root_url) unless current_user.function == "doctor"
end
def pharmacist_user
redirect_to(root_url) unless current_user.function == "pharmacist"
end
def prescription_expired?(presc)
presc.created_at < 1.month.ago
end
def signed_in_user
unless signed_in?
store_location
flash[:notice] = "Please log in."
redirect_to login_url
end
end
end
I run out of ideas so I ask you guys if anyone can help. Thanks.
There is no point in using params in your view since you already assigned those to your models. Also when you rendering your new action, those params doesn't exist as nothing has been send to the server yet. Just get rid of all the values from inputs.
Your partial should look like:
- it=f.options[:child_index].to_i
- n= it.to_s
%h2
= "Medicine ##{it+1}"
= f.hidden_field :medicine_id, :id => "my_medicine_id#{it}"
= f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path
= f.label :amount, "Amount of medicine boxes"
= f.number_field :amount
= f.label :daily
= f.number_field :daily
= f.label :period_in_days, "Duration of treatment (in days)"
= f.number_field :period_in_days
If you want your fields to have default value, set default value inside your database.