Ruby on Rails, form helper with object method - ruby-on-rails

I have a model with a method called date_string. The point of this method is to return a formatted date string when being used in a share view. Here is the view code.
<div class="field control-group">
<div class="control-label">
<%= f.label :business_hour , :date_string %>
</div>
I am expecting the f.label call to function like in this api doc, with :business_hour being the object, and :date_string being the method. However, the only thing that is rendered to the view is the string 'Date string' or 'date_string'.
Any help on getting a view class to call a method, not a property, on a model is greatly appreciated.
Business_Hour code
class BusinessHour < ActiveRecord::Base
attr_accessible :business_hourable_id,
:business_hourable_type,
:close_time, :day, :open_time,
:order , :business_date
belongs_to :business_hourable , :polymorphic => true
def date_string()
if business_date.nil?
return ''
else
return_string = business_date.strftime( '%a %b\ %e , %Y' )
end
end
end
Here is the full partial code(shared/business_hours):
<div class="field control-group">
<div class="control-label funkiness">
<%= F.label :business_hour , :date_string %>
</div>
<div class="controls">
<%= f.select :open_time, available_hours, :include_blank => true %>
</div>
<div class="control-label">
<%= f.label :open_time, 'Close Time' %>
</div>
<div class="controls">
<%= f.select :close_time, available_hours, :include_blank => true %>
</div>
</div>
Here is the pertinent part of the _form
<%= form_for (#some_show), html: {class: "form-horizontal pull-left"} do |f| %>
...
<%= f.fields_for :business_hours do |operating_time| %>
<%= render :partial => 'shared/business_hours',
:locals => {:f => operating_time} %>
<% end %>
And finally, here is the edit action of the controller
# GET /some_shows/1/edit
def edit
#some_show = SomeShow.find(params[:id])
end

So the solution that worked for me was to take the date_string off of my model, and implement it in a helper. Then, I modified my partial view so it looks like this:
<div class='field control-group hour_dropdown_2'>
<div class='field control-group'>
<div class="control-label">
<label><%= get_business_hour_string(f) %></label>
</div>
<h4 class='no-break-h'>From</h4>
<%= select :open_time, available_hours, :include_blank => false %>
<h4 class='no-break-h'>To</h4>
<%= select :close_time, available_hours, :include_blank => false %>
</div>
</div>
My select tags are still busted and I don't know why for my _address partial I get an f.whatever, but for the BusinessHour partial I get nothing in the way of form helpers.

Related

search function not working - Ruby on rails

I'm new to Ruby on Rails and trying to implement a search function with simple form to filter out availabilities results. After I press search button, it still stays on the same page and not running the search function in the controller. The permitted is false. I'm wondering why this might occur. Is there anything wrong with the search_params I wrote?
Rails version is 6.0.2.1.
views/availabilities/_searchform.html.erb
<form>
<div id="aDiv">
<%= simple_form_for :search, :url => search_rides_result_path, :method => :get do |f| %>
<div class="form-row">
<div class="form-group col-md-2">
<%= f.input :start_city, label: 'Start City', class: "form-control", error: 'Start address is mandatory, please specify one' %>
</div>
<div class="form-group col-md-4">
<%= f.input :start_street_address, label: 'Start Street Address', class: "form-control" %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-2">
<%= f.input :end_city, label: 'Destination City', class: "form-control" %>
</div>
<div class="form-group col-md-4">
<%= f.input :end_street_address, label: 'Destionation Street Address', class: "form-control" %>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-4">
<%= f.input :trip_time, as: :datetime, inline_label: 'Yes, remember me', class: "form-control" %>
</div>
<div class="form-group col-md-2">
<%= f.input :lowest_acceptable_price, label: 'Expected Price', class: "form-control" %>
</div>
</div>
<%= f.submit "Search", class: "btn btn-primary" %>
<% end %>
</div>
</form>
routes.rb file.
get 'search_rides', to: "availabilities#index"
get 'search_rides_result', to: "availabilities#search"
availabilities_controller.rb
def index
#availabilities = Availability.unmatched
end
def search
#availabilities = Availability.unmatched.search(search_params[:start_city])
end
def search_params
params.require(:search).permit(:start_city, :start_street_address, :end_city, :end_street_address, :trip_time, :lowest_acceptable_price)
end
models/availability.rb
class Availability < ApplicationRecord
has_many :users, :through => :posts
has_one :request
scope :unmatched, ->{ where(matched_request_id: -1) }
def self.search (params)
puts "start searching"
results = city_matches(start_city, end_city, params[:start_city], params[:end_city])
return nil unless results
results
end
Instead of using 2 different methods for search, try combining both in index method. Your index method will now look as follows:
def index
if params[:search]
#availabilities = Availability.unmatched.search(search_params[:start_city])
else
#availabilities = Availability.unmatched
end
end
Change the form url to search_rides_path. This way search results will be rendered in same view upon form submission.

setting a select tag on Ruby on Rails

<%= form_tag("/posts/create") do %>
<div class="form">
<div class="form-body">
<% #post.errors.full_messages.each do |message| %>
<div class="form-error">
<%= message %>
</div>
<% end %>
<div class="continent">
<label>continent<br>
<%= #post.continent %>
<%= select :continent,
[["Africa","AF"],["North America","NA"],["Oceania","OC"],["Asia","AS"],["Europe","EU"],["South America","SA"]],
:prompt => "Select" %>
</label>
</div>
<div class="country">
<label>country<br>
<%= #post.country %>
<%= select :country,
[["Japan","JP"],["China","CH"]],
:prompt => "Select" %>
</label>
</div>
<div class="title">
<label>title<br>
<textarea name="title"><%= #post.title %></textarea>
</label>
</div>
<input type="submit" value="POST">
</div>
</div>
<% end %>
I want to set a select tag for choosing user's continent and country in the form
But It doesn't work well
I've tried some way to solve this problem.
And I just got the shape which is like "Select tag" but it's only included "prompt"
Please give me some advice.
FormOptionsHelper`s select takes these args
select(object, method, choices = nil, options = {}, html_options = {}, &block)
Try explicit putting options like this:
select :post, :country, [["Japan","JP"],["China","CH"]], { :prompt => "Select" }, { other_html_options }
If you are in a form context make this
<%= form_tag("/posts/create") do |form| %>
<%= form.select :country, [["Japan","JP"],["China","CH"]], { :prompt => "Select" }, { other_html_options } %>
<% end %>
First start off by creating the correct routes:
resources :posts
In Rails you create a resource by sending a POST request to the collection path ('/posts').
Then create the form with form_for(#post) or form_with(model: #post) (Rails 5.1+) and bind the model instance to the form builder.
<%= form_for(#post) do |f| %>
<div class="form">
<div class="form-body">
<% f.object.errors.full_messages.each do |message| %>
<div class="form-error">
<%= message %>
</div>
<% end %>
<div class="continent">
<%= f.label :continent do %>
<%= f.select :continent,
[["Africa","AF"],["North America","NA"],["Oceania","OC"],["Asia","AS"],["Europe","EU"],["South America","SA"]],
prompt: "Select" %>
<% end %>
</div>
<div class="country">
<%= f.label :country do %>
<%= f.select :country,
[["Japan","JP"],["China","CH"]],
:prompt => "Select" %>
<% end %>
</div>
<div class="title">
<%= f.label :title do %>
<%= f.text_area_field :title %>
</div>
<%= f.submit %>
</div>
</div>
<% end %>
This lets you reuse the same form for updating the resource. Also when you use the input helpers rails will properly name the inputs so that you can whitelist them with:
params.require(:post).permit(:continent, :country, :title)

Rails 5.2: How to create fields_for each I18n key value?

In my _form.html.erb I have nested fields, where for an Offer I would like to save multiple Discount types with values:
<%= f.fields_for #offer.discounts do |discount| %>
<% I18n.t(:discount_type).each do |type| %>
<div class="form-group row discount-list">
<label class="col-sm-8 control-label">
<%= discount.label I18n.t("discount_type.#{type[0]}") %><br/>
</label>
<div class="col-sm-4">
<%= discount.hidden_field :discount_type, value: type[0] %>
<%= discount.number_field :value,
value: (#offer.new_record? ? '0.00' : discount.value),
class: "form-control allow_numeric" %>
</div>
</div>
<% end %>
<% end %>
At the moment my form is populated correctly as I would like it to be, however values are not saving since:
in my params I see only 1 of 3 discount types like this:
"seller_discount"=>{"discount_type"=>"special", "value"=>"5"}
there is error Unpermitted parameter: :seller_discount
records are not saving
My Seller::Offer model looks like this:
has_many :offer_discounts, class_name: "Seller::OfferDiscount"
has_many :discounts, class_name: "Seller::Discount", through: :offer_discounts, inverse_of: :offers
accepts_nested_attributes_for :discounts, allow_destroy: true
My controller is simple as:
def new
#offer = Seller::Offer.new
end
private
def offer_params
params.require(:seller_offer).permit(
:company_id, :name, :base_price,
discounts_attributes: [:id, :discount_type, :value, :_destroy]
)
end
So far I've been trying different ideas from Rails docs, however no luck. Probably in my specific case, twist is where I try to iterate over I18n.t(:discount_type) an create input field for each discount type (buy key).
I'll be happy for any hint how to solve this. Thank you!
Since you're iterating over discount_type I think that needs to be an array type in your offer_params method.
def offer_params
params.require(:seller_offer).permit(
:company_id, :name, :base_price,
seller_discounts_attributes: [:id, :discount_types => [:discount_type, :value], :_destroy]
)
end
But what happens if you try to use fields_for helper?
<%= f.fields_for #offer.discounts do |discount| %>
<%= f.fields_for I18n.t(:discount_type) do |type| %>
<div class="form-group row discount-list">
<label class="col-sm-8 control-label">
<%= discount.label I18n.t("discount_type.#{type[0]}") %><br/>
</label>
<div class="col-sm-4">
<%= discount.hidden_field :discount_type, value: type[0] %>
<%= discount.number_field :value,
value: (#offer.new_record? ? '0.00' : discount.value),
class: "form-control allow_numeric" %>
</div>
</div>
<% end %>
<% end %>
So, to have my form working for both New and Edit actions, final solution is this:
<% if params[:action] == 'new' %>
<div class="col-md-7 col-sm-7">
<!-- Discounts for new form !-->
<% I18n.t(:discount_type).each do |type| %>
<%= f.fields_for :discounts, #offer.discounts.build do |disc| %>
<div class="form-group row discount-list">
<label class="col-sm-8 control-label">
<%= disc.label I18n.t("discount_type.#{type[0]}") %><br/>
</label>
<div class="col-sm-4">
<%= disc.hidden_field :discount_type, value: type[0] %>
<%= disc.number_field :value, value: '0.00',
class: "form-control allow_numeric" %>
</div>
</div>
<% end %>
<% end %>
</div>
<% elsif params[:action] == 'edit' %>
<div class="col-md-7 col-sm-7">
<!-- Discounts for edit form !-->
<%= f.simple_fields_for :discounts do |d| %>
<div class="form-group row discount-list">
<%= d.input :discount_type, as: :hidden %>
<label class="col-sm-8 control-label">
<%= d.label I18n.t("discount_type.#{d.object.discount_type}") %><br/>
</label>
<div class="col-sm-4">
<%= d.input :value, label: false, input_html: { id: d.object.discount_type+"_discount",
class: "form-control allow_numeric" } %>
</div>
</div>
<% end %>
</div>
<% end %>
Edit action is done with simple_form_fields_for
Obviously not shiny solution, but looks like this works.

Rails form populated from one table and saving to another

Title kinda says it all, Basically i have this form
<% provide(:title, "Edit user") %>
<h1>Editing event:
<%= #newevent.id %></h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= simple_form_for #newevent do |f| %>
<div class="form-group">
<%= f.label :eventname %>
<div class="row">
<div class="col-md-6">
<%= f.text_field :eventname, :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<%= f.input :event_type, :collection => ['Concert','Festival','Sports','Theatre'] %>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :eventdesc %>
<div class="row">
<div class="col-md-6">
<%= f.text_field :eventdesc, :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :eventshortdesc %>
<div class="row">
<div class="col-md-6">
<%= f.text_field :eventshortdesc, :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :pagetitle %>
<div class="row">
<div class="col-md-6">
<%= f.text_field :pagetitle, :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :metatag %>
<div class="row">
<div class="col-md-6">
<%= f.text_field :metatag, :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :eventvenuename %>
<div class="row">
<div class="col-md-6">
<%= f.text_field :eventvenuename, :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<%= f.input :time, type: "time", :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<%= f.input :date, type: "date", :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<%= f.label :eventimage %>
<div class="row">
<div class="col-md-6">
<%= f.text_field :eventimage, :autofocus => true, class: "form-control" %>
</div>
</div>
</div>
<%= f.submit "Save changes", class: "btn btn-info" %>
<%= link_to "Delete", event_path(#newevent), :method => :delete, class: "btn btn-danger" %>
<% end %>
</div>
</div>
Here is what it loads from.
def edit
#newevent = Event.find(params[:id])
end
However its different now. I am wanting the stuff to load form the Master table (so the fields are populated from Master) However i have an update method that looks like this
def update
#newevent = Event.find(params[:id])
if #newevent.update_attributes(event_params.merge createdby: current_user.id)
flash[:success] = "Profile updated"
redirect_to "/events"
else
flash.now[:alert] = 'Error updating event'
end
end
Do i need to change something in the eventparams to get this to work (and make change from Event to Master) The fields are different in both tables, So would i need to make the value of the fields be something like this?
value: "<%=Master.name%>"
Thanks
Sam
If you're trying to load "defaults", you'd be better doing it in the model layer:
#app/models/event.rb
class Event < ActiveRecord::Base
before_create :set_defaults
private
def set_defaults
default = Master.first
self.attributes.except("id", "created_at", "updated_at").each do |field|
self[field] ||= default.send(field)
end
end
end
The above will pull a record from the Master model, populate any of the attributes in your Event model which have not been populated.
However, I believe your pattern to be inefficient.
The idea you are pulling "default" data from another model/table directly contradicts the DRY and modular principles of software development.
Not to say that if you wanted to create "dynamic" defaults for a model, your pattern might work. If you're trying to store exactly the same data in different models, you've got a problem.
I would do the following:
#app/models/event.rb
class Event < ActiveRecord::Base
##defaults: {
x: "y",
y: "z",
z: "0"
}
before_create :set_defaults
private
def set_defaults
self.attributes.except("id", "created_at", "updated_at").each do |field|
self[field] ||= ##defaults[field]
end
end
end
Update
After a discussion, it became apparent that there was more context required to understand the issue/solution fully.
The app works by importing a series of CSV data into the Master table. Whilst I don't know what data this is, the OP said that each Event would be built around the data in Master.
He mentioned he needed 3 fields definitely from Master whilst the others could be inputted by the user into Event.
This means that you could tie the two together with a has_many / belongs_to relationship:
#app/models/master.rb
class Master < ActiveRecord::Base
has_many :events
end
#app/models/event.rb
class Event < ActiveRecord::Base
belongs_to :master
end
This is a standard ActiveRecord association, which means you'll be able to call #master.events & #event.master -- accessing values from each table:
#app/controllers/events_controller.rb
class EventsController < ApplicationController
def new
#event = Event.new
end
def create
#event = Event.new event_params
#event.save
end
private
def event_params
params.require(:event).permit(:master_id, ...)
end
end
#app/views/events/new.html.erb
<%= form_for #event do |f| %>
<%= f.collection_select :master_id, Master.all, :id, :name %>
<%= f.submit %>
<% end %>
--
The reason why this will be much better than your current pattern is that each time you create a new event, you'll be able to access the master attributes:
#event.master.url #-> "url" from master record
In Rails in general you create bound form inputs by using a model and passing it to form_for (or simple_form_for).
In this case if you really need to have dynamic user editable default the most obvious solution would be to use Master to seed the new Event.
In most cases however defaults should be a developer concern which are handled on the model layer as suggested by Rich Peck.
Also setting defaults only really makes sense for a new record - why would you want to override the users choices when updating?
def new
#master = Master.last
#event = Event.new(#master.attributes.except("id", "created_at", "updated_at"))
end
<%= simple_form_for #newevent do |f| %>
<%= f.input :eventname %>
<% end %>

Prepopulate complex form values in rails edit view

I have an assessment form that renders a list of questions, and accepts answers for each question. The form data is submitted manually via ajax.
I'm having an issue when trying to pre-populate the data in my edit view. Here's how my views look:
edit.html.erb:
<div class="container">
<%= render 'assessment_form', :locals=> {:assessment => #assessment} %>
</div>
_assessment_form.html.erb:
<%= form_for #assessment do |f| %>
<%= f.submit 'Save', :class=> "btn btn-primary", :style=>"width: 100%;" %>
<div class="col-sm-2 col-sm-offset-10">
<h4>Show on Followup?</h4>
</div>
<% #assessment.questions.where(category:"S").each do |question| %>
<%= render 'question_fields', :question=> question, :f=> f %>
<% end %>
<%= f.hidden_field :patient_id, :value=> #assessment.patient.id %>
<%= f.hidden_field :template_id, :value=> #assessment.template_id %>
<% end %>
_question_fields.html.erb:
<p><%= question.content %></p>
<%= f.fields_for :answer do |builder| %>
<div class="row question">
<div class="col-sm-2 pull-right toggle">
<%= builder.check_box :tracking, {:checked=> false, :class=>"trackable", :data => {:'on-text' => "Yes", :'off-text' => "No", :'on-color'=> "success", :question => question.id}}, 0 , 1 %>
</div>
<div class="col-sm-10">
<%= builder.text_area :content, :class=>"form-control question-field", :data => {:question => question.id} %>
</div>
</div>
<% end %>
But none of the answers content are rendering in the view, the form fields are blank.
Here's an example call: Assessment.last.answers.first.content will give me the string "test". That should be showing up in my text_area box but it's not.
Just do, the instance variable #assessment is passed to the partial.
<%= render 'assessment_form' %>

Resources