I have a frontend rails app that is requesting a rails API. When my user wants to create an account, he is submitting the account form on the front-end app :
<h1>Create Account</h1>
<form action="http://localhost:3000/accounts" method="post">
<input name="authenticity_token" value="<%= form_authenticity_token %>" type="hidden">
<div class="form-group">
<%= label_tag 'account[name]', "name" %>
<input type="text" name="account[name]" required>
</div>
<div class="form-group">
<%= label_tag "account[contact_mail]", "E-Mail" %>
<input type="text" name= "account[contact_mail]" required>
</div>
<div class="form-group">
<%= label_tag "account[contact_tel]", "Telephone" %>
<input type="text" name= "account[contact_tel]" required>
</div>
<div class="form-group">
<%= label_tag "account[iban]", "Iban" %>
<input type="text" name= "account[iban]">
</div>
<div class="form-group">
<%= label_tag "account[bic]", "Bic" %>
<input type="text" name= "account[bic]">
</div>
<input type="submit">
<% if #errors %>
<ul class="list-unstyled">
<%#errors.each do |error|%>
<li class="has-error"><%=error%></li>
<% end -%>
</ul>
<% end -%>
</form>
On submit the method create from the front-end app account controller is called. The create method from the front-end app is then calling the create method on the rails API which is responsible for updating the database and rendering JSON to the front end app.
1) AccountController#create from the front-end app :
def create
# Post sur API create Account
#response = HTTParty.post(ENV['API_ADDRESS']+'api/v1/accounts',
:body => { :name => params[:account][:name],
:contact_mail => params[:account][:contact_mail],
:contact_tel => params[:account][:contact_tel],
:legal_status => params[:account][:legal_status],
:iban => params[:account][:iban],
:bic => params[:account][:bic]
}.to_json,
:headers => { 'X-User-Email' => session[:user_email], 'X-User-Token'=> session[:user_token], 'Content-Type' => 'application/json' } )
# Erreur Mauvais Auth Token
if #response["error"] == "You need to sign in or sign up before continuing."
redirect_to unauthorized_path
# erreur de validation
elsif #response["errors"]
#errors = #response["errors"]
flash[:alert] = "heello"
render :new
else
account_id = #response["account"]["id"]
redirect_to account_path(account_id)
end
end
2) AccountController#create from the API :
def create
#account = Account.new(account_params.merge(admin: current_user))
authorize #account
if #account.save
render :show
else
render_error
end
end
render error is a method that render errors in JSON format :
def render_error
render json: { errors: #account.errors.full_messages }, status: :unprocessable_entity
end
If there are validations errors when submitting the from to the API, I display them on the front end app next to the form :
<% if #errors %>
<ul class="list-unstyled">
<%#errors.each do |error|%>
<li class="has-error"><%=error%></li>
<% end -%>
</ul>
My problem is that I also wish to prepopulate the form with the data the user already submitted for better user experience.
I know there are already posts about how to prepopulate forms with rails in case of validation errors but I feel they did not really address my problem with this "double app pattern" and with my front-end app not having any models (all models / DB interactions are dealt in the API)
How can I prepopulate my form with the user's input after I receive an error from my JSON API ?
In the form you have, you could add value attributes to the input fields that populate with irb instance variables
<input type="text" name="account[name]" value="<%= #account_name %>" required>
Then in AccountController#create, set the instance variables based on the the params you received when you want to display the invalid data.
```
elsif #response["errors"]
#errors = #response["errors"]
#new code
#account_name = params[:account][:name]
#set each variable, extra to method or class for cleaner style
flash[:alert] = "heello"
render :new
```
When the form initially renders these variables will be uninitialize/nil so there will be no values in the form boxes, and then you can explicitly set them in the controller when the validation fails but you want to maintain data in the form.
This is definitely an overly-manual way to accomplish maintaining the form state, and I suggest if you want to reuse the pattern in your app you take a look at using form_for. This post might give you some insight into doing that with plain ruby objects instead of model objects. Is it possible to create form for simple class
Related
very new and need guidance, I am a very junior dev. Working on my first project: auth. project - that i've been working on for several months. but I am hitting a wall on how to pull my user.id from my User_controller and import or pull that data into my index.html.erb view.
plan is to have "user.id". render on the page with a label field dynamically. So, if a X user signs in, that "user_id" will show on this label form field by default to show X user is signed, and create some logic later to have my controller validate user and allow to prompt a new modal to change password, but when after user is login, and it routes to /dashboard view, For what ever reason, I can't get the user_id to show in my Label >user_id< using from bootstrap. I feel like this might be easy, but I'm not sure I am fully understand how rails can inject that data resource on the page dynamically
I have tried <%= #{:user_id}%>, change the label type id:/user_id with <%= #{:user_id}%>
this is what my user.controller looks like:
class UserController < ApplicationController
def index
# rendering json on page: user data
render json: User.all
end
def create
user = User.new(
first_name: params[:fname],
last_name: params[:lname],
username: params[:username],
password: params[:password],
password_confirmation: params[:password_confirmation]
)
if user.save
session[:user_id] = user.id
flash[:success] = "text"
#redirect_to '/login'
else
flash[:warning] = "text"
#redirect_to 'register'
end
end
def show
# render plain: params[:id]
#render json: userdata[:users].select {|user| user.get_id() == params[:id].to_i}
if User.exists?(params[:id])
render json: User.find(params[:id].to_i)
else
render plain: "that user doesnt exist: #{params[:id]}"
end
end
def validate
puts params
username = params[:username]
exists = User.exists?(username: username)
# puts exists
render json: {"exists": exists, "username": username}
end
end
and this is my html.erb
<% content_for :content do %>
<div class="container">
<div class="row">
<div class="col-12">
<h1 class=display-4>Welcome to your home page </h1>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-12">
<div class="jumbotron">
<p class="lead">needing to change your password - <strong class="text-success">reset your password easy</strong>.</p>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-12">
<form class="row g-3">
<div class="col-auto">
<label for="username" class="visually-hidden">Example:user_id</label>
<input type="text" readonly class="form-control-plaintext" id="username" value="Helloguy123#">
</div>
<div class="col-auto">
<label for="password" class="visually-hidden">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password">
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary mb-3">Confirm identity</button>
</div>
</form>
<% end %>
<%= render template: "layouts/application" %>
We have an application that has many models, two of them are behaving curiously (Candidate and MarketSegment).
Each entity of class Candidate holds a market_segment_id attribute. We also have a form that allows us to edit instance of Candidate and submit/update via a JSON request.
When I try to render a partial that builds the collection of radio buttons with market segment options to be selected for that candidate within the edit form, I'm always getting the last value/market_segment_id of the radio button list in params hash, that is market_segment_id => '35' every time.
We already tried many different approaches, including:
1) Inspected html to confirm if the 'collection_radio_buttons' helper is generating the right values for each button;
2) Built the loop to create each radio button with its respective attributes manually.
<%= render partial: 'shared/forms/market_segments_select', locals: {f: f} %>
ruby/erb partial content that generates radio button list
<div class="w-100 h4 overflow-scroll overflow-x-hidden bn pt3">
<%= f.collection_radio_buttons :market_segment_id, MarketSegment.all, :id, :description_pt do |m| %>
<div class="w-100 mb2 market_segment__radio-group">
<%= m.radio_button %>
<%= m.label %>
</div>
<% end %>
</div>
html generated by the partial
<div class="w-100 h4 overflow-scroll overflow-x-hidden bn pt3">
<input type="hidden" name="candidate[market_segment_id]" value="" />
<div class="w-100 mb2 market_segment__radio-group">
<input type="radio" value="1" name="candidate[market_segment_id]" id="candidate_market_segment_id_1" />
<label for="candidate_market_segment_id_1">Agronegócio e Bioenergia</label>
</div>
<div class="w-100 mb2 market_segment__radio-group">
<input type="radio" value="2" name="candidate[market_segment_id]" id="candidate_market_segment_id_2" />
<label for="candidate_market_segment_id_2">Alimentos</label>
</div>
<div class="w-100 mb2 market_segment__radio-group">
<input type="radio" value="3" name="candidate[market_segment_id]" id="candidate_market_segment_id_3" />
<label for="candidate_market_segment_id_3">Auditoria</label>
</div>
...and so on until market_segment_id = 35
params
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Sgpo39Lo...==", "candidate"=>{"avatar"=>"", ..., "market_segment_id"=>"35", ...}, "commit"=>"Atualizar", "id"=>"8"}
controller action
def update
respond_to do |format|
if #candidate.update(candidate_params)
create_candidate_skill_tags
format.html do
redirect_to admin_candidate_path(#candidate),
notice: 'Candidato atualizado com sucesso'
end
format.json { render json: #candidate, status: :ok }
else
format.html { render :edit }
format.json do
render json: #candidate.errors, status: :unprocessable_entity
end
end
end
end
Regardless of the radio button I select the params always get market_segment_id => '35' (that is the last record of the MarketSegment table.
I have done similar thing. You could do something like this
def create_candidate_skill_tags
new_skill_tags_from_params.map do |skill_text|
#candidate.skill_tags << SkillTag.where(id:
skill_text).first_or_create
end
end
<label for="users"><strong>Your Form</strong></label>
<div class="custom-select form-control pull-right">
<%= form.collection_check_boxes(:market_segment_id, MarketSegment.all, :id,
:description,
checked: #candidate.market_segments.map(&:id)) do |b| %>
<%= b.check_box %> <%= b.label %>
<% end %>
</div>
also you need in your candidate.rb
has_and_belongs_to_many :market_segments, foreign_key: :candidate_id
and in market_segment.rb
has_and_belongs_to_many :candidates
ensure you have :candidate_id column in your db. or any how you did it.
Issue: Form isn't submitting data to Orders Table
I have a form_for that is connected to 2 controllers to connect the data together once submitted. I have recently connected Stripe Elements, which has its own controller. I had a dummy form in place that when i submitted the info, the data would go through and save to the Orders Table. I deleted the form and put the elements form in place, but the way i have it set up isn't submitting to the Table.
Here's the form:
<form id="form-element" action="/charges" method="post" id="payment_form">
<%= form_for([#listing, #order]) do |form| %>
<% if #order.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#order.errors.count, "error") %> prohibited this order from being saved:</h2>
<ul>
<% order.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<script
src="https://js.stripe.com/v3/">
// data-key="pk_test_3vX123456789YKE1f0B8"
// data-amount = {#listing.price}
// data-locale="auto">
</script>
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element" class="form-control">
<!-- a Stripe Element will be inserted here. -->
</div>
<!-- Used to display form errors -->
<div id="card-errors" role="alert"></div>
</div>
<br>
<div class="form-group">
<%= form.submit "asdf", class:"ripple-effect", id:"button-element" %>
</div>
<span class="token"></span>
</form>
<% end %>
</div>
<script>
....
</script>
In my OrdersController, here's my create method:
def create
#order = Order.new(order_params)
#listing = Listing.find(params[:listing_id])
#seller = #listing.user
#order.listing_id = #listing.id
#order.buyer_id = current_user.id
#order.seller_id = #seller.id
....
Here's my ChargesController:
def create
#amount = 500
token = params[:stripeToken]
payment_form = params[:payment_form]
charge = Stripe::Charge.create({
:source => 'tok_visa',
:amount => #amount,
:description => 'Rails Stripe customer',
:currency => 'usd'
})
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
I tried throwing in orderscontroller info to the chargescontroller, and vice versa. Wouldn't work. then figured it's just the way the form is set up. So basically, if that's the solution, how can i make it so when i input the form, the data registers to the orders table.
This information may help so.. here's the dummy form that would successfully forward the information to the order table: https://pastebin.com/th2WC8Lj
I added form.submit to the stripe form, but that didn't do it. I figured it would at least create a blank order.
attempt at using ajax to asynchronously submit forms.. not working.
<script>
...
$('#Orders').on('submit', function(event) {
event.preventDefault();
$.ajax({
type: "POST",
url: "/charges",
data: $('#payment_form').serialize()
}).then(this.submit.bind(this));
});
</script>
At present, the form is posting to the charges endpoint which means only the ChargesController#create code is being called. You need to do the following:
Duplicate the charge creation code into the OrdersController#create method and remove the <form id="form-element" action="/charges" method="post" id="payment_form"> tag at the top of your code block. That will then submit the form to the OrdersController#create method.
The reason I say duplicate the code is because we don't know if charges can be created without an associated order, in which case you'd want to retain the ability to create charges independently.
I have a resource Invoice and every invoice has an edit path:
http://localhost:3000/invoices/1/edit
On my index page where I will all my invoices I want to have an input field and a submit button to jump right to the edit page for a certain invoice:
<form class="form-inline" action="???" method="get">
<div class="form-group">
<input type="text" class="form-control date" placeholder="Invoice ID" name="id" >
</div>
<button type="submit" class="btn btn-info">Show</button>
</form>
How do I have to define the action so that if I enter for example 1 and click on Show it goes right to my edit method?
I think you're looking for something like this in your html
<%= form_tag find_invoice_url do |f| %>
<%= f.text_field :invoice_number =>
<%= f.submit "Search" =>
<= end =>
then you would need to add a route
post '/invoices/find_invoice', to: "invoices#find_invoice",
as: "find_invoice"
then in your controller something like
def find_invoice
invoice = Invoice.find_by_id(params[:invoice_number])
if invoice
redirect_to invoice_url(invoice.id) #whatever your edit route is
else
redirect_to root_url #anywhere really
end
end
if you are iterating through all the invoices, you wouldn't need an input field.
assuming that you have an invoice obhect, you would just do something like
<%= form_tag edit_invoice_path(invoice), method: "get" do -%>
<%= submit_tag "Show", class="btn btn-info" %>
<% end %>
You may want the button to say edit instead - that's more of a ux "principle of least surprise" issue
I have very simple HTML (password.html.erb):
<h1>Enter business password to enter:</h1>
<input type="text" id="password" name="enter password"/>
<input type="submit" method="post" name="Submit"/>
This should, on clicking of submit, trigger an action in my controller called 'check':
def check
#entered = params['password']
if #entered == current_customer.business.manager_password_digest
puts("success!")
redirect to '/manage'
else
flash[:danger] = 'Invalid password'
render 'password'
end
end
Here is my route:
get '/password' => 'pages#password'
post '/password' => 'pages#check'
But when I click submit, nothing happens. Is it not possible to use an input in this way?
You haven't told your button to execute which action on click. for this you should use action for the submit button.
<h1>Enter business password to enter:</h1>
<input type="text" id="password" name="enter password"/>
<input type="submit" method="post" name="Submit"/ action = '/password'>
You should be using rails helpers and you need to specify the path where you want to post the data:
<h1>Enter business password to enter:</h1>
<%= form_tag("/password") do %>
<%= text_field_tag :password %>
<%= submit_tag 'Submit' %>
<% end %>