I am working on a Rails App, for which the model logic is not in the frontend, and it retreives data from the backend API.
I was referring to the form helpers guide , and in Section 2.2 Binding a Form to an Object , it explains about the binding of form to model object so new and edit form can be a single page by binding the form elements to model object.
articles_controller.rb:
def new
#article = Article.new
end
The corresponding view using form_for looks like this
articles/new.html.erb:
<% form_for :article, #article, :url => { :action => "create" }, :html => {:class => "nifty_form"} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body, :size => "60x12" %>
<%= submit_tag "Create" %>
<% end %>
http://guides.rubyonrails.org/v2.3.11/form_helpers.html
While in my code, I get the values via API call as a JSON object.
def view_request
#request_type = "View"
id = params["id"]
rest_resource = RestClient::Resource.new( ENV['TEST_API'] + "/" + id, :verify_ssl => false )
request = rest_resource.get :Authorization => cookies.signed[:remember_token], :content_type => 'application/json'
#response = JSON.parse(request)
render " request"
end
What would be the best way to create forms for both new and edit in this scenario ?
I think you want to check out form_tag. Then inside that form, you'll use tag variants, like text_field_tag.
You'll have to do a little extra work to get your one form to manage both new and edit, but it's not too bad.
BTW, in an effort to fully decouple my views from my models, I exclusively use form_tag and never access models or model instances in my views. It's a little nuts, but it helps me protect views from changes in my models.
Related
I've completed Hartl's Rails Tutorial and am now working on a project that uses the simple_calendar gem.
I want to add a dropdown to allow users to quickly navigate to a specific month and year without having to click the "next" link multiple times.
So far I have managed to create the dropdown form but I can't figure out how to set up the controller to get the url with the form parameters on submit.
This is in the partial I created that renders at the top of the monthview calendar:
<%= form_with do |form| %>
<%= select_month( Time.now, {:field_name => 'month', :id => 'month'} ) %>
<%= select_year( Date.today, {:start_year => Time.now.year,:end_year => Time.now.year+3} ,{:field_name => 'year', :id => 'year'} ) %>
<%= submit_tag("Go", :id=>"button", :class=>"date-button", :name=>"submit") %>
<% end %>
Can anyone explain how I can write the controller code to pass those parameters so that the user goes to a link like https://mycalendar.com/calendar?year=2021&month=june
Thank you for your help.
You can read the parameters directly
<%= form_with do |form| %>
<%= select_month( params[:month].present? ? Date.strptime(params[:month], '%B') : Time.now, {:field_name => 'month', :id => 'month'} ) %>
<%= select_year( params[:year].present? ? Date.strptime(params[:year], '%y') : Date.today, {:start_year => Time.now.year,:end_year => Time.now.year+3} ,{:field_name => 'year', :id => 'year'} ) %>
<%= submit_tag("Go", :id=>"button", :class=>"date-button", :name=>"submit") %>
<% end %>
But you have to add a checking for invalid date/parameters, so better do the parsing in the controller side
You can grab parameters sent to a controller via params[:parameter]. This works for both GET and POST requests. In a GET request these parameters are passed through the url, ie. /calendar?year=2021&month=june, whereas in a POST request they are passed in a formBody object.
One of the best things to do in Rails is to look at your console when a request is made. It will tell you the route, controller, action, and parameters in the log.
For a GET request you might use the method below to get the parameters.
# controller
def calendar
year = params[:year]
month = params[:month]
end
Generally a form would be sent via a PUT (create) or PATCH (update) request (known together as POST). In that case you might have a model object that the form fields would be stored in, and you would grab the parameters through a sanitization procedure. This sanitization is very important to ensure malicious code isn't passed through to your database.
def create
#event = Event.new(event_params)
...
end
private
def event_params
params.require(:event).permit(:month, :year, :title)
end
Your form_with might need a url: '/calendar' and even a method: :get to turn it into a GET request and send it to the correct route.
I am making an API call but not saving all of the data to my database, so I assumed that I do not need to make a model for that purpose. However, I do not know how to generate a form for this API call, which is in my controller.
Here is the form in my view:
<%= simple_form_for ITHINKINEEDSOMETHINGHERE url: searchApis_path, :method => 'get' do |f| %>
<%= f.input :keyword, :placeholder => 'keyword', input_html: { name: :keyword } %>
<%= f.input :city, :placeholder => 'city', input_html: { name: :keyword } %>
<%= f.input :start_date, :placeholder => 'YYYY-MM-DD', input_html: { name: :start_date } %>
<%= f.input :end_date, :placeholder => 'YYYY-MM-DD', input_html: { name: :end_date } %>
<%= f.button :submit, "Submit" %>
<% end %>
My corresponding controller:
class HomeController < ApplicationController
def index
end
def searchApis
start_date = params[:start_date]
end_date = params[:start_date]
keyword = params[:keyword]
city = params[:city]
eventbrite_request = Typhoeus::Request.new('https://www.eventbriteapi.com/v3/events/search?q='+keyword+'&sort_by=best&venue.city='+city+'&start_date.range_start='+start_date+'T00:00:00Z&start_date.range_end='+end_date+'T00:00:00Z',
method: :get,
headers: { 'Authorization' => ENV['EVENTBRITE']})
#response = eventbrite_request.run
# yelp_request = Typhoeus::Request.new('',
# )
# set #result to be the data that I want.
end
end
I am getting an "undefined method 'model_name'" error.
The route which I am making the GET request to is /searchApis, so I am guessing that the url in the form should be searchApis_path.
So far I have mainly learned how to make a form to generate a new instance of a model, but in this case, the form is to essentially initiate the API call, whose response I will later display under my form. For what it's worth, I want to later be able to save select data from the response JSON into a 'bookmarks' model.
Thanks.
Where you wrote ITHINKINEEDSOMETHINGHERE is where the record, typically an ActiveRecord model, usually goes. It is used in the construction of the various field names.
Since it looks like you're doing a search controller, you could put :search there, which then would make all your form fields named things like search[keyword]
On your backend then, you just have to access the proper params object, which is typically nested under whatever you named the record, so in this case, params[:search][:keyword].
http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for
I know you're using simple_form, but it inherits a lot from form_for, so that page is still a good reference
In a rails 4 application, I have a book resource, that is a Book model with its controller, views and route. It's what gets created by:
rails g scaffold book title
Now I want to have another set of views (and another controller) that allows to manage the same model, maybe dedicated to a different user.
I want both the creating function and the editing function to be available on this different route and view, .
Let's call it book2.
The views in the /book2 url should operate on the Book2sController.
form_for support
But the form_for guesses the submit route (and puts it in the action attribute) from the model class, that, being it always Book, lets rails guess that the submit url is /books/1 for edit or /books/ for new and not /book2s/1 for edit and /book2s/ for new as it should be.
So i found this solution, but i find it to be a bit cumbersome.
Is there anything better out there?
<%= form_for #book, :url => #book.new_record? ? url_for(book2s_path) : url_for(book2_path(#book)) do |f| %>
<%= f.text_field :title %>
<% end %>
You could set the url in your controller.
def new
# ...
#form_url = book2s_path
# ...
end
def edit
# ...
#form_url = book2_path(#book)
# ...
end
Then your view becomes:
<%= form_for #book, :url => #form_url do |f| %>
<%= f.text_field :title %>
<% end %>
I have also seen:
<%= form_for #book, :url => {:controller => 'book2s', :action => #action} do |f| %>
<%= f.text_field :title %>
<% end %>
and you just set #action in the controller (probably create or update).
Note that you don't need to include the url_for like you have.
I have a form which is always submitting the form to the "update" function in the controller, and I have created this form using "remote_form_for" tag. In this form I have objects from different tables, and from this form I want to submit entire form data to another function(not to the "update" function) via AJAX request.
I have tried many methods including using submit tag with action
<% remote_form_for #employee, :url => organization_employee_path(#organization, #employee), :method => :put do |employee_form| %>
// form objects and other functionalities
....
....
// views inside the forms
<div id="employee_header_div">
<%= render :partial => "employee_header", :locals => {:employee => #employee} %>
</div>
...
...
<%= submit_tag "page_level_validation", :id => "page_level_validation" , :action=>"validate"%>
<% end %>
But the Ajax request always calling the same "update" function.
It would be very helpful, if anyone helps to resolve this issue.
You can't set the submit to point to a different place than the main form has specified (unless you want to use the HTML5 formaction attribute and deal with the browser compatibility consequences).
However, what you could do is create a new action in your controller which deals with the situation.
e.g..
<% remote_form_for #employee, :url => organization_employee_validate_path(#organization, #employee), :method => :put do |employee_form| %>
in your controller
def validate
#do something loosely based around the update method
end
not forgetting to add the appropriate routes.
Try this:
<% form_for #employee, :remote => true, :url => organization_employee_path(#organization, #employee), :method => :put do |employee_form| %>
I am still kind of fuzzy on controllers in rails, especially so because a lot of things seem to happen magically behind the scenes, and that's not happening in this case.
So say I have a person model, which has many photos (using paperclip) and has many favorite quotes. The quotes can have the text, the attributed author, etc. In both of those models, they are set as belonging to my person model.
Within a new person form, I used some code elsewhere to create a new photo:
<% form.fields_for :screenshots, :html => { :multipart => true } do |screen_form| %>
<%= render :partial => 'screenshot', :locals => { :form => screen_form } %>
<% end %>
The partial for that is very simple, like this (minus some ajax javascript stuff I put in for nested models):
<%= form.label :photo, "Screenshot:" %>
<%= form.file_field :photo %>
This all works fine and magically the ID of the person is associated with a screenshot upon creation in person_id. I don't even have a controller for screenshots and it still works.
However, it's not working for my quotes.
<% remote_form_for :quote, :html => { :method => :put }, :url => {:controller => "quote", :action => "create", :person_id => #person.id} do |quote_form| %>
<%= render :partial => 'quote', :locals => { :form => quote_form } %>
<% end %>
The partial for this is also very simple.
<%= form.label :quote_text %>
<%= form.text_field :quote_text %>
.........
<%= form.submit 'Create' %>
I am not really sure if I can put person ID in there, but it didn't complain. However it didn't work, either. The quotes controller is very simple.
def create
#quote = Quote.create(params[:quote])
end
Currently it gets put in the DB but person_id is not populated so I can't pull up the quotes associated with a particular person. Sorry if this is a silly question, but I'm kind of learning Rails by tweaking tutorials and mashing them together so bear with me :) It's just kind of mysterious how the photo thing works with NO controllers or special stuff and this doesn't.
The first form is a person form mainly that has snapshots fields associated to it, so looking at your HTML you will find something like person[snapshots][photo], this form will be submitted to person controller.
Passing person id to second form the is key to make it work, however it's a bit weird that it's not working, the form will submit to quote controller. Did you make sure(watch the log) that the params hash has person_id attribute?