This is a process question on updating model values for an existing record. Say I have a user model. Users sign up with a name and email via devise authentication. Then I have two more forms on the site to collect additional inputs.
Form 1 stores payment data and uses the def update method. Let's say the update method has some stripe code.
Form 2 just asks for a users favorite color and wants it saved into the model. Can form 2 still use the update method with some if statement or do we need a custom route pointing to a method like def color.
I'm having trouble updating a model using form 2. And instead of posting details (done that. no solution yet) I wanted some idea on what the best process would be. It should be pretty simple to insert data into a model. I think I'm missing something basic.
Can form 2 still use the update method
Yes
Ajax
What you'll be looking for is ajax - Asynchronous Javascript & XML - a method of sending requests to your Rails server out of scope of your typical HTTP flow.
You have to remember Rails, by virtue of being built on HTTP, is stateless. This means that it has absolutely no "memory" unless, of course, you store data for future use.
The reason this is important is because when you send your "update" requests to your backend, it won't care if you've already sent a request; it will just take the data you send & blindly perform the tasks it wants:
#view
<%= form_for #user, method: :patch, remote: true, id: "form1" do |f| %>
<%= f.text_field :color %>
<%= f.submit %>
<% end %>
<%= form_for #user, method :patch, remote: true, id: "form2" do |f| %>
<%= f.text_field :other_input %>
<%= f.submit %>
<% end %>
You can read up more about Rails UJS here - both forms send the request to the update method, and will send different data. This will give you the ability to send the required data you need through two separate forms
--
Response
If you wanted to then capture the response from the forms, you'll be able to create the following Javascript:
#app/assets/javascripts/application.js
$(document).on("ajax:success", "#form1", function(status, data, xhr){
// something here
});
Related
What is the 'Rails way' to provide access to methods such as the following from a view
def approve!
self.update_attribute status, 'approved'
end
Is it best to create a link to a custom route
<%= link_to 'Approve', approve_object_path(#object) %>
#objects_controller.rb
def approve
#object.approve!
end
Or to create an update form
<%= simple_form_for #object do |f| %>
<%= f.input :status, input_html { value: 'approved' }, as: :hidden %>
<%= f.submit %>
<% end %>
On the one hand, using a form and not using the approve! method at all seems to align better with restful routes.
On the other hand, a link to a custom route seems to provide less opportunity for submitted values to be manipulated by the user, and also requires less code to implement.
Which is the preferred way to do this?
I don't know if there's a preferred best practice, per se...
Just my opinion, but I normally do the link_to approach, and for an "state machine" like your example. The need for an entire form for a simple action like this is a lot of extra code that isn't necessary when an action can be called to change the state.
The counter argument to this is that it breaks CRUD, and requires a non-CRUD route. Convention over configuration champions would probably prefer an entire new controller to change the state of the object.
TL;DR - I do the link_to approach, and I use :remote => true to make it asynchronous so the page doesn't even reload (unless you need the page to redirect elsewhere).
You can change state remotely with both the scenarios.
But I think if only a state has to be changed then use link_to. As we don't need to have form features with listed attributes in params here.
I know I've written it wrong, but I'm looking at the documentation and can't figure out how.
My model is Quote and has three fields, body, attribution, and work, all strings. The form is intended to add a new quote to a page of quotations.
on main/index.html.erb
<%= form_for(:quote, url: {action: 'create'}) do |f| %>
<%= f.text_field :body %>
<%= f.text_field :attribution %>
<%= f.text_field :work %>
<%= submit_tag "Submit" %>
<% end %>
in main_controller.rb
def create
Quote.create(body: params[:body], attribution: params[:attribution], work: params[:work])
end
The form submits, and an entry is saved to the database -- but it's a totally blank entry. I'm not sure why. Help would be appreciated!
Three things:
The way rails forms are supposed to work, you're not meant to get body, attribution, etc independently, they should be wrapped up into a quote object. But...
In your form, your not properly binding an object to the form the way rails expects. You can read more in the documentation here: http://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object. You could also generate a fake scaffold rails generate scaffold HighScore game:string score:integer to generate a fake model and see an example of how it's supposed to work. The default scaffolding even has simple examples of how to deal with save errors.
Finally, as #Paven suggested, when you get confused, be sure to look at what's going on in your log - i.e. what params are being posted to your create action. That is always helpful and a good way to diagnose problems quickly.
Your form does't need the action argument. The form_for helper uses ActiveRecord objects to determine the path, meaning as long as you build your object correctly, you won't need to determine your path individually:
<%= form_for #quote do |f| %>
Secondly, you'll want to look at your create method:
#app/controllers/quotes_controller.rb
def new
#quote = Quote.new
end
def create
#quote = Quote.new(quote_params)
end
private
def quote_params
params.require(:quote).permit(:body, :attribution, :work)
end
The problem is you're not sending an ActiveRecord object to your form_for helper. You can read the explanation here:
In Rails, this is usually achieved by creating the form using form_for
and a number of related helper methods. form_for generates an
appropriate form tag and yields a form builder object that knows the
model the form is about. Input fields are created by calling methods
defined on the form builder, which means they are able to generate the
appropriate names and default values corresponding to the model
attributes, as well as convenient IDs, etc. Conventions in the
generated field names allow controllers to receive form data nicely
structured in params with no effort on your side.
In order to get the form working correctly, you need to be able to provide a valid ActiveRecord object (#variable), which the helper can use to determine the url etc
My code above helps you provide a new ActiveRecord variable, and allows you to use it in the form. This should allow the form_for method to send your data to the create method, which will then create & save an object in the db for you
I am very new to Rails.
I am looking for the most common and 'rails-like' way to display the output of form data. I know that Simple form and Formtastic are good options to write concise code and display input fields in a user friendly manner. However, I am looking for something slightly different, I want to display the data from these forms as output, and I want to do it in a similar and concise manner. I haven't been able to find anything the last few days that I have been searching around so I figured I should ask Stack Overflow.
What do you normally do:
Write custom helpers to be able to write concise code and display the output data?
Use Simpleform/Formtastic, disable the fields, and modify the css to
make it look the way you want?
Is there a common gem that does this? Or perhaps another way I haven't thought about.
First, thanks for the initial responses. I thought I should clarify my question. Since the answers don't quite hit the mark. I already have a show method in the controller, as well as a view template for it. Currently I am displaying each field individually in the form for about 12 fields using form_for. See example snippet below:
<%= form_for(#event) do |f| %>
<div class="row-fluid">
<div class="span6">
<%= render 'shared/error_messages' %>
<%= f.label :title %>
<%= f.text_field :title, :disabled => true %>
<%= f.label :start_date %>
<%= f.date_field :start_date, :disabled => true %>
</div>
</div>
<% end %>
I guess maybe a better question would be, is their an equivalent to form_for method that display data for users, not to edit it but just to read it? It seems like their would be a a standard way to do it that I haven't discovered.
The easiest way to build forms is to use rails g scaffold Example name:string This would generate the Model, Views, Controller, and the necessary database migrations for a Model named Example with a Name attribute that is a string.
You would then use html and css to style the view how you want.
There is a ton of useful info for you on the rails guides here.
Although this question is rather ambiguous, you must appreciate that this functionality is exactly what Rails is built for (submit data & be able to display / manipulate it somewhere else)
Data
The data in an MVC application is bound by one very important factor - a database
If you're submitting data through a form, your goal is to store it in your database, and display it in other views / controller methods
Therefore, the blunt question to your answer is to abide by MVC processes, and save your data to a central repository (database or other), which you can call later:
View
To get your data into your data store, you first need to submit it
The view part of MVC is where you can display your UI, and consequently is where you can put your form. There is a whole tutorial about how to design this here, but for demonstrations' sake, here's an example of how you'd use your form:
#app/views/posts/new.html.erb
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
Controller
The data you input into your view will be sent to your controller on save
The data is sent via the HTML POST method to be read by Rails as a params[] hash. This hash contains all the sent items from your HTML form, and can be used like this:
#app/controllers/posts_controller.rb
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
end
private
def post_params
params.require(:post).permit(:title, :body)
end
Model
The .save method on your newly created Post object, basically tells your model to put the data into your database (or other data store), which you can then pull later (using the .find method or similar)
#app/models/post.rb
Class Post < ActiveRecord::Base
#stuff here
end
It's important to note your models don't store your data, they simply provide an interface (API if you will) to save the data into some sort of data store (namely, a DB)
Models are super important because they allow you to structure & relate your data, creating the ability to deploy really deep & powerful applications
When I create a form using simple_form_for #model, upon submit the post params has all the attributes grouped under params[model]. How do I get simple_form to drop this grouping and instead send it directly (under params root)?
<%= simple_form_for #user, do |f| %>
<%= f.input :name %>
<%= f.input :password %>
<%= f.submit %>
Now the name and password attributes would normally be sent under params[:user][:name], params[:user][:password] etc. How do I get simple_form to post these as params[:name], params[:password] etc.?
Thanks!
Ramkumar
ps: In case you are wondering why I need this, the bulk of my app is to serve as an API and I have built a set of methods to validate a request which expect some attributes to be in root. In a rare instance (forgot password), I actually need to present a form and I am looking for a way to use these methods.
you can explicitly define the name for an input by passing input_html to it:
input_html: { name: :name }
(needed this myself for sending an resource to a thirdparty endpoint with redirect to my side which relied on the plain attribute names, but i actually wanted not to built up label and input via the tags ;) )
also see simple form builder impl
Two ways I can think of:
The first is, don't use simple_form to build your form, but do it by hand or with the form_tag and *_tag methods. These will allow you to more closely specify what parameters are used in your form.
If you want to keep simple_form, though, then have it call a different controller action. Refactor the controllers to strip out the logic into a separate method. Something like:
class UsersController
def create_from_api
controller_logic(params)
end
def create_from_form
controller_logic(params[:user])
end
def controller_logic(params)
[actual work happens here]
end
end
I am trying to have a way of confirming the information entered before actually saving it to the DB
Considered making an individual confirmation page as discussed here
Ruby on Rails: Confirmation Page for ActiveRecord Object Creation
However my form includes an attached file using paperclip which makes it more of a hassle to implement.
I thought of just having a :confirm => pop up that would show the information that the user
had just entered.
The problem is how to show the information that the user had just entered, for example
<% form_for #entry, :html => { :multipart => true } do |f| %>
<%= f.error_messages %>
<%= f.label :name %><br />
<%= f.text_field :name %>
<%= f.label :file %><br />
<%= f.file_field :file %>
<%= f.submit 'Create', :confirm => "????? " %>
<% end %>
Given that your loading attachments it may not be a bad idea to render a staging view including information derived from the attachment allowing the user to confirm. As in display the file if it's an image, or the first paragraph of text if it's a text file, etc.
It's going to take more work than the just adding a confirm pop up, but I feel the enhanced user experience is worth the extra effort.
I'm not familiar with the way that paperclip works. So you're mostly on your own for the intimate details.
You will probably have to create a record before the staging view can be rendered with the sample of the uploaded file. To accomplish that I'd set up an "active" column on the model in question, that defaults to false.
Usage would look something like this:
User complets new form.
Attachment is updated and records are saved, with the active field set to false.
Redirected to confirmation page that is essentially the show page with a confirm link/button and a cancel link/button
a. When the confirm link/button is clicked it sends a request to the controller triggering the update action on this record setting active to true.
b. When the cancel link/button is clicked it sends a request to the controller trigering the destroy action on this record.
All that's left is to set up a recurring task to remove objects that are inactive and were crated long enough ago that it's safe to assume the user has just ended the browser session.
The confirm option for the Rails submit method can only take a text value.
If you want to dynamically generate the confirm text, one way you could do it is to write your own HTML submit tag, and write custom javascript to analyse the fields you want to use in your generated text.
Or you could use the Rails submit method, but use something like JQuery to add an event handler to it.
I'd just throw my js into an onclick handler. That's all Rails does.
<%= f.submit 'Create', :onclick => "confirm('Name is ' + $F('entry_name'));" %>
(note, didn't test that, but it looks close. confirm is a core js function, not part of any lib)