I'm currently trying to set up a payment option on my patform (part of the tutorial) through stripe. For some reason I'm getting the Nil Class error on the /add_card page when someone enters the card details in and clicks the button ADD. Not sure what am I doing wrong here.
Any ideas would be greatly appreciated!
Thanks
Users_Controller
def add_card
if current_user.stripe_id.blank?
customer = Stripe::Customer.create(
email: current_user.email
)
current_user.stripe_id = customer.id
current_user.save
#customer.sources.create(source: params[:stripeToken])
else
customer = Stripe::Customer.retrieve(current_user.stripe_id)
end
# Add Credit Card to Stripe
month, year = params[:expiry].split(/ \/ /)
new_token = Stripe::Token.create(:card =>{
:number => params[:number],
:exp_month => month,
:exp_year => year,
:cvc => params[:cvv]
})
customer.sources.create(source: new_token.id)
flash[:notice] = "Your card is saved."
redirect_to payment_method_path
rescue Stripe::CardError => e
flash[:alert] = e.message
redirect_to payment_method_path
end
Payment Form
<div class="col-md-9">
<div class="panel panel-default">
<div class="panel-heading">Payment Method</div>
<div class="panel-body">
<div class="container">
<div class='card' style="margin-bottom: 20px"></div>
<%= form_tag("/add_card", method: "post", id: "add-card") do %>
<div class="row pull-center">
<div class="col-md-12">
<div class="well">
<div class="row">
<div class="col-md-8 form-group">
<label>Card Number</label>
<input type="text" name="number" class="form-control">
</div>
<div class="col-md-4 form-group">
<label>Expiration</label>
<input type="text" placeholder="MM/YY" name="expriry" class="form-control">
</div>
</div>
<div class="row">
<div class="col-md-8 form-group">
<label>Name</label>
<input type="text" name="name" class="form-control">
</div>
<div class="col-md-4 form-group">
<label>CVV</label>
<input type="text" name="cvv" class="form-control">
</div>
</div>
<div class="row">
<div class="col-md-12 text right"></div>
<% if current_user.stripe_id.blank? %>
<button class="btn btn-normal btn-block">Addd Card</button>
<% else %>
<button class="btn btn-normal btn-block">Update Card</button>
<% end %>
</div>
</div>
</div>
</div>
<% end %>
The name of your expiry field in the form is expriry you have an extra r in there. Because of this the field you're looking at in your controller doesn't have a value so it evaluates to nil and you can't perform string methods on a nil object.
Change expriry to expiry in your form.
Related
Im stuck in a very simple problem. I am receiving an array of parameters in my view and want to iterate over the values.
This is the print of my params:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"dfOQVuXlQriII3akiGCSuMIf4i2B8c1/OX02nd6Dhy0ZKzHkhiXxlcXKCJAMFHw0vhtNKKVYuLHFo22LGsy6UQ==", "album"=>{"name"=>"asdasd", "photos_media"=>["[{\"id\":\"a245b724845f447eb63dfbaa3fba173669b55fcdf7fb55fb634707ff0c1c\",\"filename\":\"BWT_eUmU.jfif\",\"content_type\":\"image/jpeg\",\"size\":56060},{\"id\":\"1bfb4188a126079f5069c5204f8df1c7169d0464f488385ef1f8d081fcda\",\"filename\":\"drafts.png\",\"content_type\":\"image/png\",\"size\":6029}]"]}, "commit"=>"Save Album"}
My album_params are like this:
def album_params
params.require(:album).permit(:name, photos_media: [])
end
And my form:
<%= form_for #album do |f| %>
<div class="col-9">
<div class="form-group row" >
<div class="col-6">
<label for="">Name:</label>
<%= f.text_field :name %>
</div>
</div>
</div>
<div class="col-9">
<div class="form-group row" >
<div>
<div class="progress" id='progress-bar' style='display:none;'>
<div class="progress-bar progress-bar-striped active" role="progressbar" style="width: 0%"><h6>Loading...</h6>
<span class="sr-only" id='progress-bar-text'></span>
</div>
</div>
</div>
<div class="col-6">
<label for="">Add or drag photos here:</label>
<%= f.attachment_field :photos_media, multiple: true, direct: true, presigned: true %>
</div>
</div>
</div>
How can I iterate over photos_media? If I do a print on it like this:
logger.debug("******SIZE*** #{album_params[:photos_media].size} ")
It says the size is 1. Like a big string.
What im doing wrong?
As Vailisa says, photo_media contains an Array with one element that is a string:
"photos_media"=>["[{\"id\":\"a245b724845f447eb63dfbaa3fba173669b55fcdf7fb55fb634707ff0c1c\",\"filename\":\"BWT_eUmU.jfif\",\"content_type\":\"image/jpeg\",\"size\":56060},{\"id\":\"1bfb4188a126079f5069c5204f8df1c7169d0464f488385ef1f8d081fcda\",\"filename\":\"drafts.png\",\"content_type\":\"image/png\",\"size\":6029}]"]
Specifically, that string is a JSON string.
To parse that on the backend, you can try:
#photo_media_ary = JSON.parse(album_params[:album][:photos_media][0])
i keep getting this missing template error
" Missing template listings/create, application/create with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in: * "/home/codio/workspace/app/views" * "/var/lib/gems/2.2.0/gems/kaminari-0.16.3/app/views" * "/var/lib/gems/2.2.0/gems/commontator-4.10.3/app/views" * "/home/codio/.bundler/ruby/2.2.0/devise-a9d90503e903/app/views" * "/home/codio/.bundler/ruby/2.2.0/koudoku-9e73e64e5520/app/views" * "/var/lib/gems/2.2.0/gems/mailboxer-0.12.4/app/views"
,anytime i tried to create an object,after a couple of search in stack overflow , some suggest to redirect or render , initially in my create action , there was no explicit redirect and after object creation the redirect was done to the show page (the intended behavior).Tried both solutions , but still getting the same error and in my understanding there's no need to have a corresponding views for the create action.
How do i got the create action redirect to the show page without creating a
a view?.
listings_controller.rb
class ListingsController < ApplicationController
...
def create
#listing = Listing.new(listing_params)
if #listing.save
if params[:images]
params[:images].each { |image|
#listing.pictures.create(image: image)
}
end
(#users - [current_user]).each do |user|
Notification.create(recipient: user, actor: current_user, action: "posted", notifiable: #listing)
end
flash[:notice]= "L'annonce #{#listing.listing_number} a eté publiee avec succès."
respond_with(#listing)
end
end
...
end
The form that trigger the create action is rendered via a modal
_form.html.erb
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Publication d'annonce</h4>
</div>
<div class="modal-body">
<%= form_for :listing, :url => {:action => :create} do |f| %>
<div class="form-group row">
<%= f.label :name,"Titre de l'annonce", class: 'col-4 col-form-label'%>
<div class="col-8">
<%= f.text_field :name, placeholder: "Titre de l'annonce",class: "form-control here" %>
</div>
</div>
<div class="form-group row">
<%= f.label :price,"Prix d'offre", class:'col-4 col-form-label'%>
<div class="col-8">
<div class="input-group">
<div class="input-group-addon">
<i class="fa fa-usd"></i>
</div>
<%= f.text_field :price,placeholder: "Prix d'offre" ,class:"form-control here"%>
</div>
</div>
</div>
<div class="form-group row">
<%= f.label :display_usd ,'Prix en USD', class: 'col-4' %>
<div class="col-8">
<div class="form-check form-check-inline">
<label class="form-check-label">
<%= f.check_box :display_usd, class:'form-check-input' %>
USD
</label>
</div>
</div>
</div>
<div class="form-group row">
<%= f.label :category_id,class:"col-4 col-form-label" %>
<div class="col-8">
<%= f.collection_select :category_id, Category.all, :id, :name, {prompt: "choose a category"}, {class: "form-control here"}%>
</div>
</div>
<div class="form-group row">
<label for="select1" class="col-4 col-form-label">Localisation</label>
<div class="col-8">
<select id="select1" name="select1" class="form-control">
<option value="rabbit">Rabbit</option>
<option value="duck">Duck</option>
<option value="fish">Fish</option>
</select>
</div>
</div>
<div class="form-group row">
<%= f.label :image, "Image Principale", class:'col-4 col-form-label' %>
<div class="col-8">
<%= f.file_field :image, class:'form-control here'%>
</div>
</div>
<div class="form-group row">
<label class="col-4">Condition</label>
<div class="col-8">
<div class="form-check form-check-inline">
<label class="form-check-label">
<input name="radio1" type="radio" class="form-check-input" value="rabbit">
Usé
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input name="radio1" type="radio" class="form-check-input" value="duck">
Neuf
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input name="radio1" type="radio" class="form-check-input" value="fish">
normal
</label>
</div>
</div>
</div>
<div class="form-group row">
<%= f.label :description,'Produit Description', class:'col-4 col-form-label' %>
<div class="col-8">
<%= f.text_area :description,class:" form-control here " do%>
<span id="textareaHelpBlock" class="form-text text-muted">veuillez donner une description exacte de votre produit.</span>
<%end%>
</div>
</div>
<div class="form-group row">
<%= f.label :image, "Image additionel", class:'col-4 col-form-label' %>
<div class="col-8">
<%= file_field_tag "images[]", type: :file, multiple: true, class:'form-control here'%>
</div>
</div>
<div class="form-group row">
<label class="col-4">Sauvegarder sans publier</label>
<div class="col-8">
<div class="form-check form-check-inline">
<label class="form-check-label">
<input name="radio" type="radio" class="form-check-input" value="rabbit">
Unpublished
</label>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button>
<%= f.button "Publier Produit" , class: 'btn btn-primary pull-right', data: {disable_with: "<i class='fa fa-spinner fa-spin'></i> Publication en cours..."} %>
</div>
<%end%>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
This error comes if you're hitting the create action using HTML. create doesn't typically have an associated view; you use it to process an entity, and redirect the user elsewhere.
Therefore, you should just be able to use:
redirect_to #listing
at the end of your controller code.
Using #listing is a bit of Rails magic - it would more commonly appear as redirect_to listing_path(#listing).
I.E.
def create
#listing = Listing.new(listing_params)
if #listing.save
if params[:images]
params[:images].each { |image|
#listing.pictures.create(image: image)
}
end
(#users - [current_user]).each do |user|
Notification.create(recipient: user, actor: current_user, action: "posted", notifiable: #listing)
end
flash[:notice]= "L'annonce #{#listing.listing_number} a eté publiee avec succès."
redirect_to #listing
end
end
Does that do it?
Another common practice is to have different approaches depending on whether or not an object successfully saves to the db. For example:
def create
#listing = Listing.new(listing_params)
if #listing.save
...
redirect_to #listing, notice: "..."
else
flash.now[:alert] = "Listing failed to save"
render :new
end
end
A good way to play about with this is to use the generator to see how Rails handles things by default - you can use the following in the terminal to have a dig around: rails g controller test_controller.
Hope that helps - let me know if you've any questions.
I have a multistep form wizard that go through seven(7) steps.
image
Controllers:
private RegistrationEntities db = new RegistrationEntities();
public ActionResult Index()
{
return View();
}
View:
<div class="title_right">
<div class="col-md-5 col-sm-5 col-xs-12 form-group pull-right top_search">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Go!</button>
</span>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Contractors <small>Pre-Registration</small></h2>
<ul class="nav navbar-right panel_toolbox">
<li>
<a class="collapse-link"><i class="fa fa-chevron-up"></i></a>
</li>
<li class="dropdown">
<i class="fa fa-wrench"></i>
<ul class="dropdown-menu" role="menu">
<li>
Settings 1
</li>
<li>
Settings 2
</li>
</ul>
</li>
<li>
<a class="close-link"><i class="fa fa-close"></i></a>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<p>Kindly Follow the Procedures for the Pre-Registration Process.</p>
<div id="wizard" class="form_wizard wizard_horizontal">
<ul class="wizard_steps">
<li>
<a href="#step-1">
<span class="step_no">1</span>
<span class="step_descr">
Step 1<br />
<small>Step 1: Ownership Confirmation</small>
</span>
</a>
</li>
<li>
<a href="#step-2">
<span class="step_no">2</span>
<span class="step_descr">
Step 2<br />
<small>Step 2: RC Number</small>
</span>
</a>
</li>
<li>
<a href="#step-3">
<span class="step_no">3</span>
<span class="step_descr">
Step 3<br />
<small>Step 3: Company Name</small>
</span>
</a>
</li>
<li>
<a href="#step-4">
<span class="step_no">4</span>
<span class="step_descr">
Step 4<br />
<small>Step 4: TIN Number/Company Details</small>
</span>
</a>
</li>
<li>
<a href="#step-5">
<span class="step_no">5</span>
<span class="step_descr">
Step 5<br />
<small>Step 5: Company's Email</small>
</span>
</a>
</li>
<li>
<a href="#step-6">
<span class="step_no">6</span>
<span class="step_descr">
Step 6<br />
<small>Step 6: Other Company Details</small>
</span>
</a>
</li>
<li>
<a href="#step-7">
<span class="step_no">7</span>
<span class="step_descr">
Step 7<br />
<small>Step 7: Captcha</small>
</span>
</a>
</li>
</ul>
<div id="step-1">
<form class="form-horizontal form-label-left">
<div class="form-group">
<div class="col-lg-12">
<div class="col-lg-3">
<div class="form-group">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<div class="radio">
#Html.RadioButtonFor(m => m.OWNERSHIP_STRUCTURE, 1, new { #class = "DoPopup", id = "Foreign Company", value = "" }) Foreign Company
</div>
<div class="radio">
#Html.RadioButtonFor(m => m.OWNERSHIP_STRUCTURE, 2, new { #class = "DoPopup", id = "Foreign Owned Nigerian Company", value = "" }) Foreign Owned Nigerian Company
</div>
<div class="radio">
#Html.RadioButtonFor(m => m.OWNERSHIP_STRUCTURE, 3, new { #class = "DoPopup", id = "Nigerian Company", value = "" }) Nigerian Company
</div>
</div>
</div>
<div class="col-lg-3">
<div class="form-group">
</div>
</div>
</div>
</div>
</form>
</div>
<div id="step-2">
#*<h2 class="StepTitle">Step 2 Content</h2>*#
<form class="form-horizontal form-label-left">
<div class="col-lg-12">
<div class="form-group">
#Html.LabelFor(model => model.RC_NUMBER, new { #class = "col-lg-2 control-label" })
<div class="col-lg-9">
#Html.TextBoxFor(model => model.RC_NUMBER, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.RC_NUMBER)
</div>
</div>
</div>
</form>
</div>
<div id="step-3">
#*<h2 class="StepTitle">Step 3 Content</h2>*#
<form class="form-horizontal form-label-left">
<div class="form-group">
<div class="col-lg-12">
<div class="form-group">
#Html.LabelFor(model => model.COMPANY_NAME, new { #class = "col-lg-2 control-label" })
<div class="col-lg-9">
#Html.TextBoxFor(model => model.COMPANY_NAME, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.COMPANY_NAME)
</div>
</div>
</div>
</div>
</form>
</div>
<div id="step-5">
<form class="form-horizontal form-label-left">
<div class="col-lg-12">
<div class="form-group">
#Html.LabelFor(model => model.COMPANY_CONTACT_EMAIL, new { #class = "col-lg-2 control-label" })
<div class="col-lg-9">
#Html.TextBoxFor(model => model.COMPANY_CONTACT_EMAIL, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.COMPANY_CONTACT_EMAIL)
</div>
</div>
</div>
</form>
</div>
<div id="step-6">
<form class="form-horizontal form-label-left">
<div class="col-lg-12">
<div class="form-group">
<div class="col-lg-2">
Alternative E-mail
</div>
<div class="col-lg-9">
#Html.TextBoxFor(model => model.COMPANY_CONTACT_ALTERNATIVE_EMAIL, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.COMPANY_CONTACT_ALTERNATIVE_EMAIL)
</div>
</div>
</div>
<div class="col-lg-12">
<div class="form-group">
<div class="col-lg-2">
Website
</div>
<div class="col-lg-9">
#Html.TextBoxFor(model => model.WEBSITE, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.WEBSITE)
</div>
</div>
</div>
<h3>Login Details</h3>
<hr />
<div class="col-lg-12">
<div class="col-lg-1">
</div>
<div class="form-group">
<div class="col-lg-2">
Username
</div>
<div class="col-lg-8">
#*<i class="glyphicon glyphicon-user"></i>*#
<input class="form-control input-lg" name="MERGE0" id="email" type="email" placeholder="Email address" required>
</div>
</div>
<div class="col-lg-1">
</div>
</div>
<div class="col-lg-12">
<div class="col-lg-1">
</div>
<div class="form-group">
<div class="col-lg-2">
Password
</div>
<div class="col-lg-8">
#*<i class="glyphicon glyphicon-user"></i>*#
<input class="form-control input-lg" name="MERGE1" id="password" type="password" placeholder="Password" required>
</div>
</div>
<div class="col-lg-1">
</div>
</div>
</form>
</div>
<div id="step-7">
<form class="form-horizontal form-label-left">
<div class="col-lg-12">
<div class="col-lg-1">
</div>
<div class="form-group">
<div class="col-lg-10">
#Html.MathCaptcha()
#* #Html.Captcha(3)*#
<br />
<p class="Error"> #ViewBag.ErrMessage </p>
</div>
</div>
<div class="col-lg-1">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
}
<!-- jQuery Smart Wizard -->
<script>
$(document).ready(function () {
$('#wizard').smartWizard();
$('#wizard_verticle').smartWizard({
transitionEffect: 'slide'
});
$('.buttonNext').addClass('btn btn-success');
$('.buttonPrevious').addClass('btn btn-primary');
$('.buttonFinish').addClass('btn btn-default');
});
</script>
<!-- /jQuery Smart Wizard -->
The questions are:
How I I validate each step to make sure values are entered befor going to the next step
After completing the 7 steps, how do I valid that the values are entered properly before it saves.
After completing the 7th step, I clicked on the Finish button, no record was saved into the CONTRACTORS table
In step2, when RC_NUMBER is entered, it should check if it already exists. It should use it to populate COMPANY_NAME in step3, but if it doesnt exist, it should allow the user to enter COMPANY_NAME in step3
After completing the whole steps and Finish button is clicked, it should redirect to welcome model using ActionResult Welcome
Please check the answers to your questions below:
1.) jQuery SmartWizard allows us to add onLeaveStep:leaveAStepCallback field while declaring. leaveAStepCallback is the function that will be called when you click on the next button. You can implement your validation logic in this function. Please go through this URL to get the complete idea.
2.) jQuery SmartWizard also allows us to add onFinish:onFinishCallback field while declaring. In this case onFinishCallback function will be called after all the steps are completed. You can check here if all the inputs are valid and then submit the form. You must have got the idea if you had gone through the link in answer 1.
3.) You need to further elaborate why the details were not saved in DB? Is your controller action getting called? If yes, check your DB save logic to further find the issue as this is not the issue of SmartWizard.
4.) As I mentioned in the step 1 that bind a callback function to be called when next button is clicked. In this function, you can get the step number by using context.fromStep. After that you can make an ajax call to server to check if the value already exist. Implement your custom logic as required.
5.) If you are submitting form using $('form').submit(), you can redirect custom view from the controller after succesful operation. If you are making an ajax call, redirect to another controller in sucess function of ajax call.
I've been struggling with string interpolation inside an HTML accordion. It's more a logic issue that I can't seem to figure out (fairly new to rails). The problem I have is that while the layout is fine, when I click to collapse any of the 3 collapsible panels they all collapse. (Because I only have 1 #collapse).
Outermost ERB
<div class="container-fluid">
<div class="row">
<div class="col-md-2 col-sm-3">
<h2>Categorias</h2>
<div class="panel-group" id="accordion">
<%= render partial: "categories/catalog", collection: #categories, as: :c %>
</div>
</div>
_catalog Partial
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapse1">
<%= c.name %>
<span class="badge">4</span>
</a>
</h4>
</div>
<div id="collapse1" class="panel-collapse collapse in">
<% c.subcategories.each do |sc| %>
<div class="panel-body">
<a href="#">
<%= sc.name %>
</a>
</div>
<% end %>
</div>
</div>
Controller
def catalogo
#categories = Category.where("parent_id IS NULL")
unless params[:cat_id].blank?
#products = Product.where(category_id: params[:cat_id]).paginate(:page => params[:page], :per_page => 50)
else
#products = Product.all.paginate(:page => params[:page], :per_page => 50)
end
#categorieswparent = Category.where("parent_id IS NOT NULL")
end
Your IDs need to be unique. Instead of hard-coding id="collapse1", use the ID of the record:
id="collapse<%= sc.id %>"
Perform the same interpolation for the href of the <a> tag responsible for collapsing and expanding the accordion.
Use category id id="#collapse<%= c.id %>" to interpolate with element id in _catalog Partial.
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapse<%= c.id %>">
<%= c.name %>
<span class="badge">4</span>
</a>
</h4>
</div>
<div id="collapse<%= c.id %>" class="panel-collapse collapse in">
<% c.subcategories.each do |sc| %>
<div class="panel-body">
<a href="#">
<%= sc.name %>
</a>
</div>
<% end %>
</div>
</div>
Suppose there is a form page for Project, which has name and description. Take a look at the render :partial.
<div class="page-header">
<h2>{{project.id ? 'Edit ' : 'Add new'}} project</h2>
</div>
<div class="row">
<div class="col-xs-6 col-xs-offset-2">
<form class="form-horizontal">
<%= render :partial => 'templates/forms/text', :object => 'name', :locals => {:model => 'project'} %>
<%= render :partial => 'templates/forms/text', :object => 'description', :locals => {:model => 'project'} %>
<div class="form-group">
<div class="col-xs-offset-3 col-xs-9">
<button ng-click="saveProject()" type="submit" class="btn btn-success">Submit</button>
<a ng-href="{{ path('UserIndexCtrl') }}" class="btn btn-default">Back</a>
</div>
</div>
</form>
</div>
</div>
And here is a partial being used.
<div class="form-group" ng-class="{'has-error': errors.<%= text.underscore %>}">
<label for="<%= model %>.<%= text %>" class="col-xs-3 control-label"><%= text.titleize.humanize %></label>
<div class="col-xs-9">
<input id="<%= model %>.<%= text %>" name="<%= model %>.<%= text %>" type="<%= local_assigns[:type] || 'text' %>" class="form-control" ng-class="{'text-danger': true}" ng-model="<%= model %>.<%= text %>">
<span class="help-block" ng-show="errors.<%= text.underscore %>"><%= text.titleize.humanize %> {{errors.<%= text.underscore %>.join(', ')}}</span>
</div>
</div>
I am not sure this is the proper way to do a partial rendering in Rails + AngularJs combo. Wonder if there's a more angular-ish way? Thanks!
I would use a Helper to generate the input instead of writing directly in the HTML, something like:
def input_for_model(model_name, text, options = { }) # I actually have no idea what is doing your input, you can probably find a better name
options = { id: "#{model_name}.#{text}", name: "#{model_name}.#{text}",
type: 'text', class: 'form-control',
ng-class: "{'text-danger': true}",
ng-model: "#{model_name}.#{text}"
}.merge(options)
tag(:input, options)
end
And use it like this:
<div class="form-group" ng-class="{'has-error': errors.<%= text.underscore %>}">
<label for="<%= model %>.<%= text %>" class="col-xs-3 control-label"><%= text.titleize.humanize %></label>
<div class="col-xs-9">
<%= input_for_model(model, text, type: local_assigns[:type] || 'text') %>
<span class="help-block" ng-show="errors.<%= text.underscore %>"><%= text.titleize.humanize %> {{errors.<%= text.underscore %>.join(', ')}}</span>
</div>
</div>