Get value out of static rails select_tag - ruby

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.

Related

render :new is not working anymore when I'm using services

I'm trying to learn about services in Rails in order to avoid fat controllers.
Here a tried a simple product review creation
class ProductReviewsController < ApplicationController
before_action :set_product, only: :create
def new
#product_review = ProductReview.new
#product = Product.find(params[:product_id]) end
def create
if AddReviewService.call(product_review_params, #product)
redirect_to product_path(#product)
else
render :new
end
end
private
def set_product
#product = Product.find(params[:product_id]) end
def product_review_params
params.require(:product_review).permit(:content, :rating) end end
The thing is that in the case of wrong parameters for the review the render :new generates the following error :
screenshot of error received
Showing /home/miklw/code/michaelwautier/multitenant_app/app/views/product_reviews/new.html.erb where line #3 raised:
undefined method 'model_name' for nil:NilClass
Extracted source (around line #3):
1 <h1>New review for <%= #product.name %></h1>
2
3 <%= simple_form_for [#product, #product_review] do |f| %>
4 <%= f.input :content %>
5 <%= f.input :rating %>
6 <%= f.button :submit %>
Rails.root: /home/miklw/code/michaelwautier/multitenant_app
Application Trace | Framework Trace | Full Trace
app/views/product_reviews/new.html.erb:3:in `_app_views_product_reviews_new_html_erb__802305224391576972_70155240081100'
app/controllers/product_reviews_controller.rb:14:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"Z7YeYvXKKr7uYhANlevZ4H8U00p9givKzXzfue4pNFk0jE2DtTNY7Eacqati+V8IihSofLc2WPa4ZBzR2o0v5w==",
"product_review"=>{"content"=>"te", "rating"=>"9"},
"commit"=>"Create Product review",
"product_id"=>"4"}
Toggle session dump
Toggle env dump
Response
Headers:
None
In the error page console, if I type #product, I get the expected product object, but #product_review is nil.
BUT, if I use the regular way (see below), the form gets re-render as it should, with the notice message of the form
class ProductReviewsController < ApplicationController
before_action :set_product, only: :create
def new
#product_review = ProductReview.new
#product = Product.find(params[:product_id])
end
def create
#product_review = ProductReview.new(product_review_params)
#product_review.product = #product
if #product_review.save
redirect_to product_path(#product)
else
render :new
end
end
private
def set_product
#product = Product.find(params[:product_id])
end
def product_review_params
params.require(:product_review).permit(:content, :rating)
end
end
Any idea what could cause this issue ?
EDIT : Here is the service I call :
class AddReviewService < ApplicationService
attr_reader :content, :rating
def initialize(params, product)
#content = params[:content]
#rating = params[:rating]
#product = product
end
def call
review = ProductReview.new(content: #content, rating: #rating)
review.product = #product
return true if review.save
return false
end
end
EDIT 2 : returning the review when saved
def call
review = ProductReview.new(content: #content, rating: #rating)
review.product = #product
return review if review.save
return false
end

Search form with two fields not working

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

Ajax and Ruby on Rails with local variable?

I really don't get how to use Ajax with Ruby on Rails. I must be missing something simple.
What I want to do is to ask the user to select a date, and then make a table of documents appear, but only with the selected date (Date is an attribute of Document).
My idea is to create a local variable witch is not in my database, store the selected date in it, and then create a loop in my view saying for example #document.where(:date = date).each...
In app/controllers/documents_controller.rb, I have :
class DocumentsController < ApplicationController
def information
#documents = Document.all
#date = params[:date]
respond_to do |format|
format.html # index.html.erb
format.js{}
format.json { render json: #documents}
end
end
end
And in app/views/documents/_information.js.erb, I have:
<%= form_tag(document, :remote => true) do %>
<%= label_tag(:date, "The selected date is:") %>
<%= text_field_tag(:date) %>
<%= submit_tag %>
<% end %>
In the end, I have a field where the user puts his date, but the submit button doesn't do anything.
What do I miss ?
As discussed you need to change the flow of your app.Lets go through steps one by one
a. create your input field where you are selecting your date field. You already have your form for that
<%= form_tag(you_path_for_information_method, :remote => true) do %>
<%= label_tag(:date, "The selected date is:") %>
<%= text_field_tag(:date) %>
<%= label_tag(:portfolio, "Add portfolio") %>
<%= text_field_tag(:portfolio) %>
<%= submit_tag %>
<% end %>
In controller
def information
#documents = Document.all
#date = params[:date]
#portfolio = Portfolio.find(params[:portfolio])
respond_to do |format|
format.js{}
end
end
In your information.js.erb you can have:
$("#some_id_of_parent").html("<%=j render partial: "your_partial", locals: {portfolio: #portfolio} %>")

Getting params value in rails create method from controller

My code has send s
<% url = url_for(:controller => 'boxelements', :action => 'new', :project_id => #project.id, :author_id => User.current.id) %>
<%= link_to "Upload New File",url %>
from new method I can get the param values
def new
#boxelement = Boxelement.new
puts params[:project_id]
puts params[:author_id]
end
Here is how I send this value as a form input
<%= f.hidden_field :project_id, :value =>project_id %>
<%= f.hidden_field :author_id, :value =>User.current.id %>
I need to access those value from create method of the controller
def create
#boxelement = Boxelement.new(params[:boxelement])
if #boxelement.save
puts params[:project_id]
puts params[:author_id]
end
end
This code shows nothing when they are in create method of controller.
puts params[:project_id]
puts params[:author_id]
What's wrong with my code?
From this line I can assume you want to access params of :boxelement
#boxelement = Boxelement.new(params[:boxelement])
use the following line in order to access the params value.
puts params[:boxelement][:project_id]
puts params[:boxelement][:author_id]

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