Search form with two fields not working - ruby

I'm making an RoR app that allows users to CRUD guidelines. I also am adding various search functions, including the option to search by two attributes "investor" and "program", which are two text fields in my search form. It's not working. My logic works when searching by one attribute, but not two. This is almost certainly due to me not understanding how to send two text fields as params to a search function, and I can't seem to find enough documentation to find the answer myself.
my model file:
def self.invprogsearch(params[:investor], params[:program])
where(['investor LIKE? && program LIKE?', "%#{investor}%", "%#{program}%"])
end
my index controller
def index
if params[:invprogsearch]
#guidelines = Guideline.invprogsearch(params[:invprogsearch])
else
#guidelines = Guideline.all
end
end
and my search form
<p>Search by Investor and Program</p>
<%= form_tag(guidelines_path, :method => "get", id: "search-form") do %>
<%= text_field(:guideline, :program_code, placeholder: "Enter investor") %>
<%= text_field(:guideline, :investor, placeholder: "Enter program") %>
<%= submit_tag "Search", :name => nil %>
<% end %>
I appreciate the help here, I'm anxious to become more proficient in Ruby/Rails

Try to rework your code like that :
View :
<p>Search by Investor and Program</p>
<%= form_tag(guidelines_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :program_code, nil, placeholder: "Enter investor" %>
<%= text_field_tag :investor, nil, placeholder: "Enter program" %>
<%= submit_tag "Search", :name => nil %>
<% end %>
Model:
def self.invprogsearch(params)
where('investor LIKE ? AND program LIKE ?', "%#{params[:investor]}%", "%#{params[:program_code]}%")
end
Controller :
def index
if params[:program_code].present? && params[:investor].present?
#guidelines = Guideline.invprogsearch(params)
else
#guidelines = Guideline.all
end
end
end
Also, here is a cool screencast about implementing a search feature :
https://www.codeschool.com/screencasts/basecamp-search

Your model should read
def self.invprogsearch(investor, program)
where(['investor LIKE ? && program LIKE ?', "%#{investor}%", "%#{program}%"])
end
params is not set at the time your model definition is being read.
And the controller should say
def index
if params[:invprogsearch]
#guidelines = Guideline.invprogsearch(params[:investor], params[:program_code])
# ^----- Change here
else
#guidelines = Guideline.all
end
end
The basic problem is that the names of the fields in your form need to match up with the named of the fields in params that you pass into your model.

I hope this helps.
Is a good idea to handle scopes for reusage
class Guideline < ActiveRecord::Base
scope :by_program_code, -> (program_code) {
if program_code.present?
where(arel_table[:program_code].match("%#{program_code}%"))
else
current_scope
end
}
scope :by_investor, -> (investor) {
if investor.present?
where(arel_table[:investor].match("%#{investor}%"))
else
current_scope
end
}
scope :by_program_code_and_investor -> (program_code, investor) {
by_program_code(program_code).by_investor(investor)
}
end
And in controller
class GuidelinesController < ApplicationController
before_action :guidelines, only: [:index]
def index; end
protected
def guidelines
if params[:program_code] && params[:investor]
#guidelines ||= Guideline.by_program_code_and_investor(params[:program_code], params[:investor])
end
#guidelines ||= Guideline.all
end
end
If you want a more flexible search
def guidelines
#guidelines = Guideline
#guidelines = #guidelines.by_program_code(params[:program_code]) if params[:program_code]
#guidelines = #guidelines.by_investor(params[:investor]) if params[:investor]
#guidelines = #guidelines.all
end

Related

Get value out of static rails select_tag

I have just started out programming with ruby on rails. I really like it, but sometimes it's really complicated. What I am trying to do is to get the selected value out of the select_tag and pass it to the Model where I will multiply the value to another one (that comes from an from_for textfield).
The problem is I wasn't able to figure out how to get the value from the View to the Controller and then to the Model.
Here is my code:
View:
<%= label_tag 'Remind' %>
<%= f.number_field :remind %>
<%= select_tag :select_conv, options_for_select([['Day', 1], ['Week', 7], ['Month', 30]]) %>
Controller:
def create
add = Item.new(item_params)
if add.save
flash[:notice] = ''
redirect_to items_path
else
redirect_to new_item_path
flash[:error] = ''
end
private
def item_params
params.require(:item).permit(:itemname, :amount, :bbf, :remind)
end
end
Model:
def convert_to_d
convert = self.remind * self.v_convertor
self.assign_attributes(remind: convert)
end
Thank you in advance
You have to do some changes:
View:
<%= label_tag 'Remind' %>
<%= f.number_field :remind %>
<%= select_tag :select_conv, options_for_select([['Day', 1], ['Week', 7], ['Month', 30]]) %>
From the View, it will return a hash with the values of each user's input. So, for this example, it will return:
params = { remind: user_input, select_conv: user_input }
You can catch that in your controller with the method item_params, but
you have to specify the parameters that you want in your method, so your item_params should be:
Controller:
def create
add = Item.new(item_params)
if add.save
flash[:notice] = ''
redirect_to items_path
else
redirect_to new_item_path
flash[:error] = ''
end
end
private
def item_params
params.require(:item).permit(:itemname, :amount, :bbf, :remind, :select_conv) # << update here
end
In your model, you can access the values saved in item_params with their names, as you did with self.remind, you can call it with self.select_conv.
Model:
# self.select_conv can be used now.
def convert_to_d
convert = self.remind * self.v_convertor
self.assign_attributes(remind: convert)
end
You can also use some validations in your model to guarantee integrity from the user's data. For more information about validations.

passing multiple id with URL using Rails 3

my requirement is passing array of ids with URL and extract them into controller method.Suppose I have the ids like below.
#userid=[1,2,3,4]
I have the link_to tag like below.
<%= link_to "update",users_update_path(:all_id=#userid) %>
In users_controller.rb file i want to access all id which are present in #userid variable.
users_controller.rb:
class UsersController < ApplicationController
def update
end
end
Please help me to resolve this issue.
convert the array into string and pass string to controller like
<% c= #userid.join(‘,’) %>
<%= link_to "update",users_update_path(:ids => c) %>
in controller using split method convert string back to array
class UsersController < ApplicationController
def update
s = params[:ids]
#ids = s.split(/,/)
end
end
in routes.rb
match ‘your_users_update_path/:ids’ => ‘users#update’
You can try this, I hope this will help.
<%= link_to "update",users_update_path(params.merge!(:all_id => [1,2,3,4])) %>
## Output
puts params[:all_id]
[1,2,3,4]
Try this:
<%= link_to "update",users_update_path(:all_id => #userid.to_s) %>
users_controller.rb:
class UsersController < ApplicationController
def update
#user_ids = params[:all_id]
end
end

Rails 4. Moving form information from one controller (with no model), to another (no model) in order to pass arguments to a method

I have a simple app where users will be able to purchase items. On item pages there will be an add to cart button. The carts-controller displays the items using REDIS relationship, it has no model. Once the user has reviewed the items and wishes to buy, they will be directed to purchases view where once they pay with stripe, an order will be created in purchases-controller. The purchases controller also has no model.
The user.rb model:
class User < ActiveRecord::Base
has_many :orders
def get_cart_items
cart_ids = REDIS.smembers "cart#{id}"
Item.find(cart_ids)
end
def purchase_cart_items!(recipient_name:, recipient_address:)
get_cart_items.each { |item| purchase!(item, recipient_name, recipient_address) }
REDIS.del "cart#{id}"
end
def purchase!(item, recipient_name, recipient_address)
self.orders.create!(user_email: self.email,
item_id: item.id,
recipient_name: recipient_name)
recipient_address: recipient_address)
end
end
The purchases-controller:
class PurchasesController < ApplicationController
def create
Stripe::Charge.create(
...
)
##########
current_user.purchase_cart_items!(recipient_name:, recipient_address:)
##########
end
end
The carts-controller:
class CartsController < ApplicationController
def create
REDIS.sadd current_user_cart, params[:item_id]
end
def destroy
REDIS.srem current_user_cart, params[:item_id]
end
end
Creating the Order attributes of user_email: and item_id: is easy by calling self.email and item.id since they are attached to a model, but I am unsure of how to use a form in the carts view to have the user input the recipient_name: and recipient_address: arguments for purchase_cart_items!(recipient_name:, recipient_address:) method in the purchases-controller.
I need to:
Create a form in the carts view where the user can input arguments for a method in another controller
Upon submission of the form details, I need the user to be redirected to purchases view
The form information has to be then passed as an argument to a method in the purchases-controller
Thanks!
A form_tag with a GET method needs to be used in order to submit the form info to the right controller.
In the carts view:
<%= form_tag({controller: "purchases", action: "new"}, method: "get") do %>
<%= label_tag 'recipient name: ' %>
<%= text_field_tag 'recipient_name' %>
<%= label_tag 'recipient address: ' %>
<%= text_field_tag 'recipient_address' %>
<%= submit_tag "PAY" %>
<% end %>
Once in the new action of the purchases-controller I used params to get the form info and session to make the form information available to the create action in the same controller:
class PurchasesController < ApplicationController
def new
#name = params[:name]
#address = params[:address]
session[:name] = #name
session[:address] = #address
end
def create
Stripe::Charge.create(
...
)
##########
#name = session[:name]
#address = session[:address]
current_user.purchase_cart_destinations!(name: #name, address: #address)
##########
end
end
Once the form information was accessible in the create action of purchases-controller, the keyword arguments for current_user.purchase_cart_items! were easy to set with instance variables of #name and #address.

Not showing created blog entries

I'm fairly new to Rails and learning to create a blog using this tutorial. On step 10, once I define create and show, after creating a new post in browser I don't see any entries on show with id page. All I see is heading and and blank title and post header.
Following is my controller -
class PostController < ApplicationController
def index
end
def new
end
def create
#post = Post.new(params[:posts])
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
end
Show view ---
<h1>Show a post</h1>
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Text:</strong>
<%= #post.text %>
</p>
Route ---
RailsBlog::Application.routes.draw do
resources :post
root :to => "post#index"
end
Form ---
<%= form_for :post, url: {action: 'create'} do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit 'Submit' %>
</p>
<% end %>
May be this is just a spelling mistake, but since I've recently started learning Rails, I'm unable to resolve this.
Update: I can go to particular id using
http://localhost:3000/post/1
but am only seeing blank page with view headers
The problem is here:
#post = Post.new(params[:posts])
It should be params[:post] - singular, not plural.
Also note that the best practice with form_for is to pass an object instead of symbol:
form_for #post do |f|
Then:
You don't need to specify url
You can reuse the same form for an edit action or create action (if object creation failed due to failing validation)
This however requires to initialize new object in your new action:
def new
#post = Post.new
end
UPDATE:
Also your routes are incorrect. When defining plural resources, you need to use plural form (it's more the convention than requirement, but since you're learning stick with it). So change your routes to:
resources :posts
And rename your controller to PostsController (remember to rename file name as well). restart the server and all should work.
ANOTHER UPDATE:
You also need to rename folder app/views/post to app/view/posts.
AND YET ANOTHER UPDATE:
In rails 4, you are not allowed to mass assign any params which has not been whitelisted using strong parameters. You need to tell rails which fields you allow to be assigned first - this is a security thing. You need to make some changes to your controller:
class PostsController < ApplicationController
...
def create
#post = Post.new(post_params)
...
end
...
private
def post_params
params.require(:post).permit(:title, :text)
end
end
This is the way to tell your controller that you are expecting those attributes from your form and they can be safely assigned.
I had just similar problem on the same tutorial.
The code spelling was correct and clearly accorded to examples in tutorial and BroiSatse's answer above.
The mistake was in order of private method definition.
How it was:
...
private
def post_params
params.require(:post).permit(:title, :text)
end
def show
#post = Post.find(params[:id])
end
...
The working order:
def show
#post = Post.find(params[:id])
end
private
...
Anyway, this topic was rather helpful. Thak you for your answers!

Multiple Contact Forms - Rails 3

I am relative newbie to all this, so sorry if this sounds mad!
I have used this tutorial: http://www.railsmine.net/2010/03/rails-3-action-mailer-example.html
And I have a new contact form working great.
The controller is at app/controllers/support_controller.rb
class SupportsController < ApplicationController
def new
# id is required to deal with form
#support = Support.new(:id => 1)
end
def create
#support = Support.new(params[:support])
if #support.save
redirect_to('/', :notice => "Support was successfully sent.")
else
flash[:alert] = "You must fill all fields."
render 'new'
end
end
end
And the model at /app/models/support.rb
class Support
include ActiveModel::Validations
validates_presence_of :email, :sender_name, :support_type, :content
# to deal with form, you must have an id attribute
attr_accessor :id, :email, :sender_name, :support_type, :content
def initialize(attributes = {})
attributes.each do |key, value|
self.send("#{key}=", value)
end
#attributes = attributes
end
def read_attribute_for_validation(key)
#attributes[key]
end
def to_key
end
def save
if self.valid?
Notifier.support_notification(self).deliver!
return true
end
return false
end
end
The views however only work in views/supports/new.html.rb (rendered - views/supports/_form.html.erb)
So I can call the Model / Controller from localhost:3000/support/new but if I try and render the same form in another view from the root directory e.g. app/view/contact.html.erb I get:
undefined method `model_name' for NilClass:Class
I think this is because it is calling the support model away from the supports directory.
Do I have to create an instance on #support so it can be called? If so what is the best way of doing that? I think I am nearly there. I just want the contact form on multiple pages not just in suppport/new
Thanks
Charlie
Yes, you would need to create a #support variable in each action you wish to render your form.
Another option would be to refactor the form to take a parameter, that way you're a bit more flexible. For example, from your view:
<%= render :partial => "supports/form", :locals => {:support => #support} %>
Now, instead of referring to #support in your _form.html.erb, you'd refer to simply support as it's a local_assign.
Yet another option would be to refactor the form a little further, and worry about creating the actual form tag outside of the partial.
Such as:
app/views/supports/new.html.erb
<%= form_for #support do |form| %>
<%= render :partial => "suppports/form", :object => form %>
<% end %>
app/views/supports/_form.html.erb
<%= form.text_field :foo %>
<%= form.text_field :bar %>
...
In this case, when you render a partial with the object option, you will get a local variable in your partial with the same name as the partial. You maintain a little bit more flexibility in the path of your form, but can still render the meat of what a Support object is inside of the form while remaining consistent across your app.
To clarify, you could use this somewhere else by doing something like:
app/views/foos/_create_foo_support.html.erb
<%= form_for #foo.support do |form| %>
<%= render :partial => "supports/form", :object => form %>
<% end %>
You have to pass #support object wherever you use your contact form. It's working in SupportsController#new because you initialize the variable there. In all other places where you want to use the form, you'll have to do the same.

Resources