Making dynamic search form to stop bloating Controller - ruby-on-rails

I have a search form with 2 ways of searching records, name and email.
<%= form_tag(clients_path, method: :get, class: "d-flex") do %>
<%= text_field_tag(:client_name, params[:client_name], placeholder: "Buscar por nombre", class: "form-control") %>
<%= text_field_tag(:client_email, params[:client_email], placeholder: "Buscar por email", class: "form-control") %>
<%= submit_tag ("Buscar"), class: "btn btn-primary" %>
<% end %>
In my controller
if params[:client_name]
#clients = User.where(name: params[:name])
else
#clients = User.all
end
if params[:client_email]
#clients = User.where(email: params[:client_email])
else
#clients = User.all
end
This works only when searching for 1 condition.
How can I make my controller code dynamic and check if any of conditions are made, show the corresponding results in my #clients variable? I don't want to bloat my controller...
Thanks!

I would change it to:
#clients = User.all
#clients = #clients.where(name: params[:name]) if params[:name]
#clients = #clients.where(email: params[:client_email]) if params[:client_email]

Related

Rails: Get params from click

I'm working on a Pinterest-like app to learn Rails, where users can collect items and add them to collections.
I have an "Add to collection" button which opens a modal with a list of all collections of a user. This works fine on individual item show pages, but not on my item index page (which lists all items that have been posted).
This is my collections controller:
def index
#item = Item.find(params[:item_id])
#selected_collections = selected_collections(#item.id)
#collections = current_user.collections
respond_to do |format|
format.js {
render
}
end
end
My items controller:
def index
#items = Item.all.order(created_at: :desc).paginate(:page => params[:page], :per_page => 20)
#collections = current_user.collections
#selected_collections = selected_collections(item.id)
end
def show
#item = Item.find_by_id(params[:id])
return render_not_found if #item.blank?
#collections = current_user.collections
#selected_collections = selected_collections(#item.id)
end
This is my Add-to-collection button, which should be shown for each item on the index:
<%= link_to "+ Add", item_collections_path(item, format: :js), class: 'btn btn-secondary btn-30', data: {toggle: 'modal', target: '#CollectionModal'}, remote: true, format: :js %>
And part of the corresponding modal:
<div class="modal-body">
<%= render 'collections/collections_list', :collections=>#collections, :selected_collections=>#selected_collections %>
</div>
_collection_list.html.erb
<div id="collection_list">
<% #collections.each do |collection| %>
<%= render 'collections/collection_checkbox', collection: collection, selected_collections: selected_collections %>
<% end %>
<%= render 'collections/collection_checkbox', collection: Collection.new, selected_collections: selected_collections %>
<div style='display: none;' class="new_collection_template">
<%= render 'collections/collection_checkbox', collection: Collection.new, selected_collections: selected_collections %>
</div>
_collection_checkbox.html.erb
<div class="form-check">
" <%= 'checked' if selected_collections.include?(collection.id) %> <%= "disabled" unless collection.id %>>
<%= collection.collection_name %>
<% if !collection.id %>
<input type="text" class="collection-name" placeholder="New collection" />
<% end %>
On my index I get the following error message:
undefined local variable or method `item' for
ItemsController:0x007f69022aefa0 Did you mean? item_url items_url item_path #items
Screenshot of Error Message
I assume that this is because I don't have individual #item defined on my index. On the item show pages I can simply find the params in the URL. But how can I solve this problem on the index?
Thanks for your help, much appreciated :)

Ruby Problems Displaying Variables From New View, but Not Edit

In my app I have a quiz in a partial because I need the same (lengthy) quiz for my new and for my edit view. In the header of the application.html.erb and on my users#show page I display the results from this quiz, once it is taken, using an if/else statement. For some reason, after a user takes the quiz in the new view it is registering that the quiz has been completed (you can tell by the if/else statement) but not displaying the variables. However, using the edit view (that calls the same partial _quiz.html.erb) the variables display perfectly.
My new view calls the partial like this:
<%= render partial: "quiz", locals: { url: swing_books_path, method: :post } %>
While my edit view calls it like this:
<%= render partial: "quiz", locals: { url: edit_swing_book_path(#swing_book), method: :put } %>
The partial looks like this:
<%= form_for #swing_book do |f| %>
<div class="clearfix">
<h1 class="text-center">
<%= f.text_field :swing01, class: 'form-control input-1' %>
<%= f.text_field :swing02, class: 'form-control input-1' %>
<%= f.text_field :swing03, class: 'form-control input-1' %>
-
<%= f.text_field :swing04, class: 'form-control input-1' %>
<%= f.text_field :swing05, class: 'form-control input-1' %>
<%= f.text_field :swing06, class: 'form-control input-1' %>
-
<%= f.text_field :swing07, class: 'form-control input-1' %>
<%= f.text_field :swing08, class: 'form-control input-1' %>
<%= f.text_field :swing09, class: 'form-control input-1' %>
<%= f.text_field :swing10, class: 'form-control input-1' %>
</h1>
<div class="form-group text-center">
<%= f.submit "Submit Swing Code", class: 'btn btn-success' %>
</div>
</div>
<% end %>
However, I use these exact same details (with just the variable names changed) on another quiz that is not having the same issue. (I have three other similar quizzes all of which display perfectly from both new and edit views.)
My model looks like this:
class SwingBook < ActiveRecord::Base
before_save :set_swing_code
def set_swing_code
self.swing_code = "#{self.swing01}#{self.swing02}#{self.swing03}-#{self.swing04}#{self.swing05}#{self.swing06}-#{self.swing07}#{self.swing08}#{self.swing09}#{self.swing10}"
end
belongs_to :user
validates :user, presence: true
end
My controller looks like this:
class SwingBooksController < ApplicationController
before_action :require_sign_in
def show
#swing_book = SwingBook.find(params[:id])
end
def new
#swing_book = current_user.build_swing_book
end
def create
#swing_book = SwingBook.new
#swing_book.swing_code = params[:swing_book][:swing01]
#swing_book.swing_code = params[:swing_book][:swing02]
#swing_book.swing_code = params[:swing_book][:swing03]
#swing_book.swing_code = params[:swing_book][:swing04]
#swing_book.swing_code = params[:swing_book][:swing05]
#swing_book.swing_code = params[:swing_book][:swing06]
#swing_book.swing_code = params[:swing_book][:swing07]
#swing_book.swing_code = params[:swing_book][:swing08]
#swing_book.swing_code = params[:swing_book][:swing09]
#swing_book.swing_code = params[:swing_book][:swing10]
#swing_book.swing_code = params[:swing_book][:swing_code]
#swing_book.user = current_user
if #swing_book.save
flash[:notice] = "Your swing code was saved successfully."
redirect_to user_path(current_user)
else
flash[:alert] = "Sorry, your results failed to save."
redirect_to welcome_index_path
end
end
def edit
#swing_book = SwingBook.find(params[:id])
end
def update
#swing_book = SwingBook.find(params[:id])
#swing_book.assign_attributes(swing_book_params)
if #swing_book.save
flash[:notice] = "Results were updated successfully."
redirect_to user_path(current_user)
else
flash.now[:alert] = "There was an error saving your results. Please try again."
redirect_to welcome_index_path
end
end
private
def swing_book_params
params.require(:swing_book).permit(:swing01, :swing02, :swing03, :swing04, :swing05, :swing06, :swing07, :swing08, :swing09, :swing10, :swing_code)
end
end
Finally, here's the logic I'm using to display these variables in the application.html.erb file:
<% if current_user.swing_book != nil %>
<p>ID Code:
<%= current_user.swing_book.swing01 %>
<%= current_user.swing_book.swing02 %>
<%= current_user.swing_book.swing03 %>
-
<%= current_user.swing_book.swing04 %>
<%= current_user.swing_book.swing05 %>
<%= current_user.swing_book.swing06 %>
-
<%= current_user.swing_book.swing07 %>
<%= current_user.swing_book.swing08 %>
<%= current_user.swing_book.swing09 %>
<%= current_user.swing_book.swing10 %></p>
<% end %>
And on the user#show page:
<% if #user.swing_book == nil %>
<h3>ID Code: ???-???-????<%= %></h3>
<p><%= link_to "Get Your ID Code Now!", new_swing_book_path %></p>
<% else %>
<h3>ID Code:
<%= #user.swing_book.swing01 %>
<%= #user.swing_book.swing02 %>
<%= #user.swing_book.swing03 %>
-
<%= #user.swing_book.swing04 %>
<%= #user.swing_book.swing05 %>
<%= #user.swing_book.swing06 %>
-
<%= #user.swing_book.swing07 %>
<%= #user.swing_book.swing08 %>
<%= #user.swing_book.swing09 %>
<%= #user.swing_book.swing10 %></h3>
<p><%= link_to "Update Your Code", edit_swing_book_path(#user.swing_book) %></p>
<% end %>
I originally tried displaying just the swing_code variable (as established in the method, but it was displaying a single integer so I switched to the code seen above. Ideally, I would like to display it as just the swing_code variable, but the (somewhat repetitive) workaround I'm currently using works fine-ish if I could only get the new/edit display issue worked out.
Any ideas as to what could be going wrong? I can't find any differences between this and the other quizzes that could be causing a problem!
In your create method, you have a block of code that explicitly sets the #swing_book values. This code is setting all of the values from the form into just the swing_code member. Since the last assignment is also from the swing_code param to the swing_code member, it's hiding the mistake. Here's the code with the correct member fields assigned:
#swing_book.swing01 = params[:swing_book][:swing01]
#swing_book.swing02 = params[:swing_book][:swing02]
#swing_book.swing03 = params[:swing_book][:swing03]
#swing_book.swing04 = params[:swing_book][:swing04]
#swing_book.swing05 = params[:swing_book][:swing05]
#swing_book.swing06 = params[:swing_book][:swing06]
#swing_book.swing07 = params[:swing_book][:swing07]
#swing_book.swing08 = params[:swing_book][:swing08]
#swing_book.swing09 = params[:swing_book][:swing09]
#swing_book.swing10 = params[:swing_book][:swing10]
#swing_book.swing_code = params[:swing_book][:swing_code]
Now, while that will fix the immediate problem, you probably just want to use the same approach as the update method. Try this for your create method, instead:
def create
#swing_book = SwingBook.new
#swing_book.assign_attributes(swing_book_params)
#swing_book.user = current_user
if #swing_book.save
flash[:notice] = "Your swing code was saved successfully."
redirect_to user_path(current_user)
else
flash[:alert] = "Sorry, your results failed to save."
redirect_to welcome_index_path
end
end
However, you have an opportunity to minimize the overall code to help eliminate errors like this. Consider something like this for your controller code:
class SwingBooksController < ApplicationController
before_action :require_sign_in
def show
#swing_book = SwingBook.find(params[:id])
end
def new
#swing_book = current_user.build_swing_book
end
def edit
#swing_book = SwingBook.find(params[:id])
end
def create
#swing_book = SwingBook.new
apply_form_values
end
def update
#swing_book = SwingBook.find(params[:id])
apply_form_values
end
private
def apply_form_values
#swing_book.assign_attributes(swing_book_params)
if #swing_book.save
flash[:notice] = "Results were updated successfully."
redirect_to user_path(current_user)
else
flash.now[:alert] = "There was an error saving your results. Please try again."
redirect_to welcome_index_path
end
end
def swing_book_params
params.require(:swing_book).permit(:swing01, :swing02, :swing03, :swing04, :swing05, :swing06, :swing07, :swing08, :swing09, :swing10, :swing_code)
end
end
You can use techniques like this to make it easier to write your initial code, and make it far easier to maintain.

rails faux active record

I am trying to use faux active record (a model that has no persistence in db).
I followed this example:
https://quickleft.com/blog/using-faux-activerecord-models-in-rails-3/
And I have this error:
ArgumentError in SearchController#new
wrong number of arguments (2 for 1)
app/models/search.rb:32:in assign_attributes'
app/models/search.rb:27:ininitialize'
app/controllers/search_controller.rb:4:in new'
app/controllers/search_controller.rb:4:innew'
It seems that when you call Search.new it needs the parametters but my goal is to make it an empty Search object.
Here are my model, controller, view, route:
Model
class Search
include ActiveModel::MassAssignmentSecurity
TRUE_VALUES = ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
attr_accessor :query
attr_reader :safe_search, :results_per_page
alias_method :safe_search?, :safe_search
attr_accessible :query, :safe_search, :results_per_page
RESULTS_PER_PAGE = [10, 25, 50, 100].freeze
include ActiveModel::Conversion
include ActiveModel::Validations
validates :query, presence: true
validates :results_per_page, presence: true, inclusion: { in: RESULTS_PER_PAGE }
def persisted?
false
end
def initialize(attributes = {})
assign_attributes(attributes)
yield(self) if block_given?
end
def assign_attributes(values, options = {})
sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
send("#{k}=", v)
end
end
def results_per_page=(value)
#results_per_page = value.to_i
end
def safe_search=(value)
#safe_search = TRUE_VALUES.include?(value)
end
end
Controller
class SearchController < ApplicationController
def new
#search = Search.new
render "search/new.html.erb"
end
def create
#search = Search.new(params[:search])
# TODO: use the #search object to perform a search. Adding
# a `results` method on the search object might be a good starting point.
end
end
View: search/new.html.erb
<%= form_for #search do |f| %>
<%= f.label :query %>
<%= f.text_field :query %>
<%= f.label :safe_search %>
<%= f.check_box :safe_search %>
<%= f.label :results_per_page %>
<%= f.select_box :results_per_page %>
<%= end %>
Here is the solution that I found:
In the model I am using this:
def initialize(attributes = {})
assign_attributes(attributes)
end
def assign_attributes(attributes)
sanitize_for_mass_assignment(attributes).each do |k, v|
send("#{k}=", v)
end
end
Here are my new and create methods in the controller:
def new
#search = Search.new
render "search/new.html.erb"
end
def create
#search = Search.new(params[:search])
respond_to do |format|
format.html { render :template => "search/create.html.erb" }
end
end
By the way i had to rename my controller to SearchesController because controllers must be pluralized.
And here is my new.html.erb view:
<%= form_for #search, url: { action: "create" }, :method => :post do |f| %>
<%= f.label :query %>
<%= f.text_field :query %>
<%= f.label :safe_search %>
<%= f.check_box :safe_search %>
<%= f.label :results_per_page %>
<%= f.select(:results_per_page, [10, 25, 50, 100]) %>
<%= f.submit %>
<% end %>
I hope this will be useful to somebody.

wrong number of arguments (1 for 0) in sunspots

My Controller:
def index
#search = Onj.search do
fulltext params [:search]
end
#onjs = #search.results
logger.debug params
end
index.html.erb:
<%= form_tag onj_index_path, :method => :get do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
Error is:
ArgumentError in OnjController#index
wrong number of arguments (1 for 0)
" def index
#search = Onj.search do
fulltext params [:search]
end
#onjs = #search.results "
Remove the space in params [:search] on line 3 in index method.

Passing parsed variables into different models form

I have a products scaffold set up, and I just created a new foo controller and view. In my foo controller I parse a url, and get back an arry of objects. How can I pass each of these variables into the products form as defaults?
my controller:
require 'net/http'
require 'json'
def index
if params[:commit] == "Add Product"
#productId = params[:q]
#resultsReceived = true
if
url = URI.parse("url" + params[:q].to_s)
#response = JSON.parse(Net::HTTP.get_response(url).body)
end
else
#resultsReceived = false
#response = []
end
respond_to do |format|
format.html
end
end
end
My current index
<%= form_tag("/foo", :method => "get") do %>
<%= label_tag(:q, "Enter Product Number") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Add Product") %>
<% end %>
<% if #resultsReceived == true %>
Title: <%= #response["product"]["title"] %> </br>
ID_Str: <%= #response["product"]["id_str"] %> </br>
Image Url: <%= #response["product"]["image_url"] %> </br>
Base Item Price: <%= #response["product"]["base_item_price"] %> </br>
Current Item Price: <%= #response["product"]["price"] %> </br>
Seller Name: <%= #response["product"]["mp_seller_name"] %> </br>
Description: <%= #response["product"]["descr"] %> </br>
<% end %>
I want the variable above to be passed to my already existing products from.
I think you have to move the access of the other data from your index action to either your your new action, or an action you create 'new_prefilled' possibly. It would helpful if the attributes matched (the stuff you get from the url has the same attribute names as your product model)
i.e.
def new_prefilled
if url = URI.parse("url" + params[:oid].to_s)
#response = JSON.parse(Net::HTTP.get_response(url).body)
end
#product = Product.new(#response['product'])
render 'new'
end
Then you'd have to add a route,
get '/products/new/:oid' => 'products#new_prefilled'
Then in your index action, you would do this:
if params[:commit] == "Add Product"
redirect_to "/products/new/#{params[:q]}"
end
So you would render your new products view, but it would be pre-filled with that data you got from the other site.

Resources