Rails populate edit form for non-column attributes - ruby-on-rails

I have the following form:
<% form_for(#account, :url => admin_accounts_path) do |f| %>
<%= f.error_messages %>
<%= render :partial => 'form', :locals => {:f => f} %>
<h2>Account Details</h2>
<% f.fields_for :customer do |customer_fields| %>
<p>
<%= customer_fields.label :company %><br />
<%= customer_fields.text_field :company %>
</p>
<p>
<%= customer_fields.label :first_name %><br />
<%= customer_fields.text_field :first_name %>
</p>
<p>
<%= customer_fields.label :last_name %><br />
<%= customer_fields.text_field :last_name %>
</p>
<p>
<%= customer_fields.label :phone %><br />
<%= customer_fields.text_field :phone %>
</p>
<% end %>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
As well as
attr_accessor :customer
And I have a before_create method for the account model which does not store the customer_fields, but instead uses them to submit data to an API.. The only thing I store are in the form partial..
The problem I'm running into is that when a validation error gets thrown, the page renders the new action (expected) but none of the non-column attributes within the Account Detail form will show?
Any ideas as to how I can change this code around a bit to make this work me??
This same solution may be the help I need for the edit form, I have a getter for the data which it asks the API for, but without place a :value => "asdf" within each text box, it doesn't populate the fields either..

Okay, what you need to do is create a class to handle your customer with and without a Braintree gateway connection. First, create the class:
class Customer
attr_accessor :company, :first_name, :last_name, :phone, :gateway
def initialize gateway_id=nil
begin
#gateway = Braintree::Customer.find(gateway_id) unless gateway_id.nil?
rescue Braintree::NotFoundError
end
end
def company
#gateway.nil? ? #company : #gateway.company
end
# Implement the rest of the methods this way as well. You can even use
# meta-programming so that you don't repeat yourself.
end
You'll notice that calling Customer.new(id).company will work with and without an id or gateway, because if a gateway non-existent #company will be returned, and if a gateway is present the gateway's company will be returned.
Finally, hook this into your model:
class Account
def customer
#customer ||= Customer.new(self.gateway_customer_id)
end
def customer= h
#customer = Customer.new
#customer.company = h[:company]
...
#customer
end
end
You'll have to modify how you write code to the API so that you use customer.company instead of customer[:company] for example, but you can probably write a function within the Customer class to do this easily.
You'll have to modify your form to:
<% f.fields_for :customer, #account.customer do |customer_fields| %>

Related

how to update nested attribute in form

I wanna update the nested attribute but failed, for example there is a Article, and a book has many comments. when I find the comment I have written has some mistakes, so I wanna modify it.
here is my code.
In code_snippet.rb:
class CodeSnippet < ApplicationRecord
has_many :annotations, dependent: :destroy
accepts_nested_attributes_for :annotations ,update_only: true ,reject_if: :all_blank, allow_destroy: true
end
In annotation.rb:
class Annotation < ApplicationRecord
belongs_to :code_snippet
end
In code_snippet_controller.rb:
def edit
#code_snippet = CodeSnippet.find(params[:id])
end
def update
#code_snippet = CodeSnippet.find(params[:id])
if #code_snippet.update(code_snippet_params)
redirect_to #code_snippet
else
render 'edit'
end
end
private
def code_snippet_params
params.require(:code_snippet).permit(:snippet)
end
In annotation.rb:
def edit
#code_snippet = CodeSnippet.find(params[:code_snippet_id])
#annotation = #code_snippet.annotations.find(params[:id])
end
def update
#code_snippet = CodeSnippet.find(params[:id])
#annotation = #code_snippet.annotations.find(params[:id])
if #annotation.update(annotation_params)
redirect_to #code_snippet
else
render 'edit'
end
end
In 'views/code_snippets/show.html.rb'
<div>
<h2>Annotations</h2>
<%= render #code_snippet.annotations %>
</div>
In 'views/annotations/_annotation.html.erb'
<p>
<strong>User:</strong>
<%= annotation.user %>
</p>
<p>
<strong>Line:</strong>
<%= annotation.line %>
</p>
<p>
<strong>Body:</strong>
<%= annotation.body %>
</p>
<p>
<%= link_to "Edit", edit_code_snippet_annotation_path(annotation.code_snippet,annotation) ,controller: 'annotation'%>
</p>
In 'views/annotations/edit.html.erb':
<%= form_for(#code_snippet) do |f| %>
<%= f.fields_for :annotation,method: :patch do |builder| %>
<p>
<%= builder.label :user %><br>
<%= builder.text_field :user %>
</p>
<p>
<%= builder.label :line %><br>
<%= builder.text_field :line %>
</p>
<p>
<%= builder.label :body %><br>
<%= builder.text_area :body %>
</p>
<p>
<%= builder.submit %>
</p>
<% end %>
<% end %>
what I wanna update the annotation without change the codesnippets. what should I do to change my code.
So.... There's a lot going on here so I'm going to start by suggesting a careful look at the docs
Firstly, let's look at your form:
CodeSnippet has_many :annotations
So your fields_for statement should be for :annotations, not :annotation. The fields for statement also should not take a method options key.
Next your code_snippets_controller:
As indicated by the docs, the parameter sent back from the nested attributes form will be under the key: annotations_attributes and will contain a hash of arrays.
You need to allow this attribute, and any attribute you wish to pass onto the annotation model with strong parameters:
params.require(:code_snippet).permit(annotations_attributes: [:some, : permitted, :params])
I believe this is all you need to get your example working. But, if you run into more troubles, I recommend a spending some quality time with a few binding.pry statements to introspect on the actual behaviour of your code.

How can I render a _form file from a different controller without having conflicting form_for's?

Let's say I have 2 models, Box.rb and Toy.rb. Rails gives me pages and methods to create new toys and boxes independently. However, I would like to ensure/provide the ability to create a box's first toy when creating a box for the first time.
In line with DRY, I wanted to simply put <%= render "Toy/form" %> inside the _form.html.erb file that is made for Box.
The problem is that Toy's _form file contains, well, a form_for method for obvious reasons. It's a problem for what I am trying to do because I will end up with 1 form nested in the other, while all I really want is to get the Toy fields while keeping to DRY…?
You should be using accepts_nested_attributes_for along with fields_for.Assuming your associations are like this
#box.rb
Class Box < ActiveRecord::Base
has_many :toys
accepts_nested_attributes_for :toys
end
#toy.rb
Class Toy < ActiveRecord::Base
belongs_to :box
end
#box_controller.rb
def new
#box = Box.new
#toy = #box.toys.build
end
def create
#box = Box.new(box_params)
if #box.save
-----
else
-----
end
end
private
def box_params
params.require(:box).permit(:box_attribute_1,:box_attribute_2,:more_box_attributes, toys_attributes: [:toy_attribute_1,:more_toy_attributes])
end
In your box/form,you can do like this
<%= form_for(#box) do |f| %>
<div class="field">
<%= f.label :box_attribute_1 %><br />
<%= f.text_field :box_attribute_1 %>
</div>
<div class="field">
<%= f.label :box_attribute_2 %><br />
<%= f.text_field :box_attribute_2 %>
</div>
<div class="field">
<%= f.label :box_attribute_3 %><br />
<%= f.text_field :box_attribute_3 %>
</div>
<%= f.fields_for #toy do |builder| %>
<%= render 'toys/form', :f => builder %>
<% end %>
<% end %>

rails getting value from view to conroller

Having an issue getting a value from a form to the controller. I am using rails 4.0.
My view looks like this (new.html.erb)
<h1> POST A NEW LISTING </h>
<% if current_user.nil? %>
<h2>You must be logged in to view this page </h2>
<% else %>
<%= form_for [#user, #listing] do |f| %>
<%= f.label :title, 'Title' %> <br />
<%= f.text_field :title %>
<%= f.label :general_info, 'General Information' %> <br />
<%= f.text_area :general_info %>
<%= f.label :included, 'Included' %> <br />
<%= f.text_field :included %>
<%= f.label :length, 'Length' %> <br />
<%= f.text_field :length %>
<%= f.label :price, 'Price' %> <br />
<%= f.text_field :price %>
<%= fields_for #tagging do |u| %>
<%= u.label :tag, 'Tag' %> <br />
<%= u.text_field :tag %>
<% end %>
<%= f.submit "submit" %>
<% end %>
<% end %>
I am trying to add tags. I have 2 models to handle the tags:
models -> tag.rb
class Tag < ActiveRecord::Base
has_many :taggings
has_many :listings, through: :taggings
end
models -> tagging.rb
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :listing
end
tags keep track of the tag names themselves, while taggings keeps track of the connection to the listings.
When a user submits the form they will type in a string tag such as: "exampletag". I then need to search my tag model to get the tag_id of that specific tag. If it exists I need to put the tag_id and listing_id into taggings. Currently I have the listing_id correct, but I am having a problem even accessing the :tag symbol from the form.
This is what I have so far. Not that currently :tag_id is hardcoded in because I cant get #current_tag to return the information I need.
listings_conroller.rb #create
def create
#user = User.find(current_user.id)
#listing = #user.listings.build(listing_params)
#save before we get the listing ID
if #listing.save
#current_tag = Tag.where(:name => params[:tag])
#taggings = Tagging.new(:tag_id => 1, :listing_id => #listing.id)
if #taggings.save
flash[:success] = "Success"
redirect_to root_path
else
render :action => 'new'
end
else
render :action => 'new'
end
end
I thought that #current_tag = Tag.where(:name => params[:tag]) would return the correct listing but it seems to be returning null when I submit the form with a name which is in the database.
got it!
Since tags is nested under taggings I needed to access the param as:
params[:tagging][:tag]
instead of params[:tag]

Polymorphic user model when using devise

I am building a job board and therefore have two user models and employer and an applicant.
I am using devise and therefore my challenge now is to use this with the polymorphic relationship.
Through some rails console testing I know that (resource) in devise passes all the user information and it is passing the role_type which is either applicant or employer. However it is set to nil and therefore although my user is being saved it is not saving the role type of applicant or employer. Furthermore nothing is being saved in the applicant or employer tables just in the user table. My code is below but my question really is how do I pass the role_type to the devise resource hash? Or if this isnt possible the most elegant way of solving this problem.
Many Thanks!
Also the full project code is here if I have missed anything https://github.com/PatGW/jobs
Below is the views->devise->user->new.html.erb
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2> Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</p>
<p>
<%= radio_button_tag :role_type, "employer", :checked => false %><br />
<%= label :role_type, 'Employer' %>
</p>
<p>
<%= radio_button_tag :role_type, "applicant", :checked => true %><br />
<%= label :role_type, 'Applicant' %>
</p>
<p class="button"><%= f.submit %></p>
<% end %>
UsersController which inherits from DeviseController
class UsersController < Devise::RegistrationsController
def new
super
end
def create
User.transaction do
super
after_sign_in_path(resource)
end
end
private
def after_sign_in_path(resource)
debugger
#user = User.new(params[:user])
if params[:role_type] == "coach"
role = Employer.create
else params[:role_type] == "player"
role = Applicant.create
end
end
end
The problem here is not Devise related, but association / OO related. I checked out your code: Your applicant and employer model seem to HAVE a user field, while those models should actually inherit from user, for they ARE a kind of user. So, try this:
class Employer < User
attr_accessible :location, :logo, :name
end
for starters, and see if it helps. (Btw: Obviously, you should also change the code for applicant)

Creating forms for Multiple Nested Resources in Rails 3

I have been following Ryan Bates' tutorial on nested forms Railscast 196
The form for the new action shows the nested attributes for quizzes but does not show nested attributes for the key. I am guessing this is because quizzes have a has_many relationship where key has a has_one relationship... But I cannot figure out what I'm doing wrong?
Any help is much appreciated!
This is my model:
class Repository < ActiveRecord::Base
has_many :quizzes, :dependent => :destroy
has_one :key, :dependent => :destroy
accepts_nested_attributes_for :key, :quizzes
end
This is my controller:
def new
#repository = Repository.new
3.times { #repository.quizzes.build }
#repository.key = Key.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #repository }
end
end
This is my view:
<div class="field">
<%= f.label :wp_uid %><br />
<%= f.text_field :wp_uid %>
<% f.fields_for :quizzes do |quiz_fields| %>
<p>
<%= quiz_fields.label :name, "Name" %><br />
<%= quiz_fields.text_field :name %>
</p>
<% end %>
<% f.fields_for :key do |key_fields| %>
<div class="field">
<%= key_fields.label :value, "Value" %><br />
<%= key_fields.text_field :value %>
</div>
<div class="field">
<%= key_fields.label :expiry, "Expiry" %><br />
<%= key_fields.date_select :expiry %>
</div>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You should try modifying your fields_for blocks to use <%= %>
Try changing to:
<%= f.fields_for :key do |key_fields| %>
The railscast could have been made before the change in Rails 3 to use <%= %> instead of <%%>.
Ryan has a nested_form gem that you may find useful for this as well. I haven't tried using it yet, but plan to next time I start a new project.
https://github.com/ryanb/nested_form
Try building the key object as
#reposity.build_key
From the rails docmentation
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Unsaved+objects+and+associations
If you wish to assign an object to a has_one association without saving it, use the build_association method. The object being replaced will still be saved to update its foreign key.

Resources