Ruby Model - set value on initializate - ruby-on-rails

I'm starting with ruby on rails. I have a simple scaffold.
Here is my model:
class Pet < ActiveRecord::Base
belongs_to :user
belongs_to :petRace
attr_accessible :birth, :exactAge, :nick
def initialize
birth = DateTime.now.in_time_zone.midnight
end
end
the html code
<%= form_for #pet, :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :nick, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :nick, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :birth, :class => 'control-label' %>
<div class="controls">
<div class="input-append date datepicker" data-date="<%=#pet.birth.strftime("%d/%m/%Y") %>" data-date-format="dd/mm/yyyy">
<%= f.text_field :birth, :class => 'input-append', :value => #pet.birth.strftime("%d/%m/%Y") %>
<span class="add-on"><i class="icon-th"></i></span>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
pets_path, :class => 'btn' %>
</div>
<% end %>
the controller:
def new
#pet = Pet.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #pet }
end
end
I just replace the original code for the :birth attribute, as you can see here:
<%= f.text_field :birth, :class => 'input-append', :value => #pet.birth.strftime("%d/%m/%Y") %>
when i select the option new the birth property seems to be no value and i get this execption
undefined method `[]' for nil:NilClass
Extracted source (around line #11):
8:
9: </script>
10: <%end%>
11: <%= form_for #pet, :html => { :class => 'form-horizontal' } do |f| %>
12: <div class="control-group">
13: <%= f.label :nick, :class => 'control-label' %>
14: <div class="controls">
app/views/pets/_form.html.erb:11:in `_app_views_pets__form_html_erb__3291519358612565784_70159905628180'
app/views/pets/new.html.erb:4:in `_app_views_pets_new_html_erb__1494749415896629355_70159907398120'
app/controllers/pets_controller.rb:28:in `new'
It's my understanding that the birth value is set with the actual date and time(in the initialize method). Am i wrong or missing something? When i edit a record i have no problem.
Thanks in advance.

There are a variety of ways to set a default value as #Rob mentioned in his comment.
A callback as #Dave mentioned in his comment is an OK idea, too.
I suspect the main reason the after_initialize approach isn't working for you is that you need to explicitly use self as in self.birth = rather than birth =. Ruby thinks you are defining a local variable named birth rather than assigning a value to ActiveRecord's attribute birth that is implemented via method_missing internally. This is why #pet.birth is nil even though it might appear that you assigned a value to it.
Also note that the after_initialize callback will be called even for persisted objects when you instantiate them by loading them from the database. It is also called after the attributes are assigned via initialize for new records. Thus to prevent the user-specified value from being trampled on by your default (for both persisted and new records), be sure to do something like this:
self.birth = value if birth.nil?
Emphasis on the if birth.nil?

Well here is the solution. First of all, the after_initialize method was not executed. But after this modification it worked:
class Pet < ActiveRecord::Base
belongs_to :user
belongs_to :petRace
attr_accessible :birth, :exactAge, :nick
after_initialize :init
protected
def init
self.birth = DateTime.now.in_time_zone.midnight
end
end

Related

How can I update two User objects in the same Rails form_for?

I'm trying to use a form_for in rails to update two objects from the User model at the same time. The reason is that a person can update basic information for both themselves and their spouse (two different users), without having to fill out two separate forms.
My current code for updating one user looks like this:
<%= form_for(#user, :url=> wizard_path, :method => :put) do |f| %>
<div class="form-group form-question-group">
<%= f.label :state, "What state do you live in?", class: "form-question" %>
<%= f.select(:state, options_for_select(us_states, selected: #user.state), {:prompt => "State"}, :class => "form-control", :required => true) %>
<%= f.hidden_field :user_id, value: #user.id %>
</div>
<div class="form-buttons">
<%= link_to "Back", previous_wizard_path, :class => "align-left" %>
<%= f.submit "Continue", :class => "btn btn-primary align-right" %>
</div>
<% end %>
How can I edit this form so that on submit it updates not just the current user, but also the user's spouse (which can be accessed by #user.spouse).
my idea is using your user controller update method
def update
if #user.update_attributes(user_params)
# here you update spouse
spouse = #user.spouse
if spouse.present?
spouse.state = #user.state
spouse.save
end
flash[:success] = 'success'
end
end
This sounds like the classic use case for ActiveRecord::NestedAttributes.
Nested attributes allow you to save attributes on associated records
through the parent. By default nested attribute updating is turned off
and you can enable it using the accepts_nested_attributes_for class
method. When you enable nested attributes an attribute writer is
defined on the model.
class User
belongs_to :spouse
accepts_nested_attributes_for :spouse
end
<%= form_for(#user, :url=> wizard_path, :method => :put) do |f| %>
# ...
<%= f.fields_for :spouse do |sf| %>
<%= sf.label :name, 'Your spouses name' %>
<%= sf.text_field :name %>
<% end %
<% end %>
def user_params
params.require(:user)
.permit(:foo, :bar, :baz, spouse_attributes: [:id, :name, :email]) # ...
end
Since this is handled on the model layer you don't have to do anything in your controller besides whitelisting the nested attributes.

Rails 4 - associations between controllers, id not getting passed

I have two controllers categories and products. Products belongs to categories but I'm having trouble setting up the relationship.
In category.rb
has_many :products
In product.rb
belongs_to :category
validates :category_id, :presence => true
validates :name, :presence => true, :uniqueness => true
When I try to create a new product, the record does not save because category_id is blank. My product form looks like so:
<%= form_for #product, :html => { :class => 'form-horizontal' } do |f| %>
<%= f.hidden_field('category_id', :value => params[:category_id]) %>
<div class="control-group">
<%= f.label :name, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :name, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :category, :class => 'control-label' %>
<div class="controls">
<% #cat = Category.all %>
<%= select_tag 'category', options_from_collection_for_select(#cat, 'id', 'name') %>
</div>
</div>
<div class="control-group">
<%= f.label :price, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :price, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :description, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :description, :class => "tinymce", :rows => 10, :cols => 120 %>
<%= tinymce %>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
products_path, :class => 'btn' %>
</div>
<% end %>
and in the products controller I have:
def new
#product = Product.new
#category = #product.category
end
I've tried looking through other questions on SO but haven't had any luck finding the correct way to pass the category id to products.
I hope I've been clear enough and I'm happy to provide any extra information that may be needed.
EDIT
I've made the following changes to the products controller as suggested by I not get the error: Cannot find Category without an ID
before_filter :set_category, only: [:create]
def set_category
#category = Category.find(params[:category_id])
end
def create
#product = #category.products.new(product_params)
#....
end
I'm using nested routes like so:
resources :categories do
resources :products
end
You should set product's category in create action:
def create
#product = #category.products.new(product_params)
# ...
end
in new action, you should just have
def create
#product = Product.new
end
Of course, you need to set #category (#category = Category.find(params[:category_id])) instance variable before (in before_filter, for example).
You should also remove this hidden field from view and remove category_id from allowed params if you don't want users to set category_id manually and set form_for arguments properly, since you're using nested resources:
form_for [#category, #product]

Rails show form value only if condition

Hello i have a form like
<%= form_for #user,
:url => url_for(:controller => 'frontend',
:action => 'registration_completion') do |f| %>
<div class="control-group">
<%= f.label :name, "Jméno", :class => 'control-label' %>
<div class="controls">
<%= f.text_field :name, :class => 'text_field' %>
</div>
</div>
And user is displaying the form where he can see already registered values, but some of that value i want to hide if some condition (specifically i need hide value of username if it contains #) It is possible? thank you
solution: it seems that
<% if #user.name.include?('#') %>
<%= f.text_field :name %>
<% else %>
<%= f.text_field :name, :value => "" %>
<% end %>
works
I strongly suggest to put your logic inside a helper method:
module UserHelper
def name_input(instance, f, options = {})
options[:html_options] ||= {}
f.text_field :name, options[:html_options] if instance.name.include?('#')
end
end
Then in your view:
<%= name_input(#user, f, html_options: { class: 'text_field' }) %>
If you want to simply hide the value you can do:
<%= f.text_field :name, value: #user.name.include?('#') ? #user.name : '' %>
Feel free to move this to a helper method also.
To create a hidden field when the username contains an # symbol you could use the following helper method
module UserHelper
def hidden_name_field(user, f, options = {})
options[:html_options] ||= {}
if user.name.include?('#')
f.hidden_field(:name, options[:html_options])
else
f.text_field(:name, options[:html_options])
end
end
end
and use it in you form:
<%= hidden_name_field(#user, f, html_options: { class: 'text_field' }) %>

Virtual attribute allways nil in custom validation method

because I'm pretty new to Ruby on Rails I'll explain what I did. I've got a virtual attribute in my model called testing. I've defined it like this:
class Comment < ActiveRecord::Base
attr_accessor :testing
attr_accessible :user_name, :comment, :user, :testing
I then added custom method for custom validation like this:
validate :custom_validation
I also added the method, of course:
def custom_validation
# a bit of custom_validation
end
I then added a field in my form:
<%= form_for(#comment) do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<%= f.hidden_field :post_id, :value => #post.id %>
<% if !signed_in? %>
<div class="field">
<%= f.label :user_name %>
<%= f.text_field :user_name, :class => "user_field" %>
</div>
<% else %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<% end %>
<div class="field">
<%= f.label :comment %>
<%= f.text_area :comment, :style => "height: 50px; width: 80%;" %>
</div>
<div class="field pin">
<%= f.label :testint %>
<%= f.text_field :testing, :class => "user_field" %>
</div>
<div class="buttons">
<%= f.submit "Speichern" %>
</div>
<% end %>
That's all I did. So please don't assume I did something else I didn't describe here, because I didn't ;)
My problem is, that my virtual field testing is always nil inside of my custom_validation method. Unless I run the validation in the console:
co = Comment.new
co.testing = "Hello"
co.valid?
I've checked using the logger. If I run via the console the testing-field isn't nil. If I run it via the browser, it is. It seems that the parameter is somehow not passed to the model correctly. I hope I just missed something really obvious. Hope you can help me.
Cheers,
Michael
It has to do with what's in your create or update actions. The scaffold generator will put in code to set real attributes, but does not call setter methods from attr_accessor.
add attr_reader :testing to your model!

undefined method "_index_path" form_for problem

I'm trying to generate a form using the form_for helper in RoR but I am encountering what seems to be a routing error. Here are the relevant files:
models/equipment.rb
class Equipment < ActiveRecord::Base
attr_accessible :name, :tracking_number
validates :tracking_number, :presence => true,
:uniqueness => { :case_sensitive => true }
end
controllers/equipments_controllers.rb
class EquipmentsController < ApplicationController
def index
#equipments = Equipment.paginate(:page => params[:page])
end
def new
#equipment = Equipment.new
end
end
views/equipments/new.html.rb
<h1>Add an equipment</h1>
<%= form_for (#equipment) do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<div class="field">
<%= f.label :name %> <br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :tracking_number %><br />
<%= f.text_field :tracking_number %>
</div>
<%= f.submit "Add" %>
<% end %>
routes.rb
EquipmentTracking::Application.routes.draw do
root :to => "equipments#index"
resources :equipments
end
I don't see anything wrong but they output the following:
NoMethodError in Equipments#new
Showing /opt/ror/equipment_tracking/app/views/equipments/new.html.erb where line #2 raised:
undefined method `equipment_index_path' for #<#<Class:0xb6725a2c>:0xb6724640>
If I changed it to
<%= form_for (:equipment) do |f| %>
it seems to work ok. I'm also certain that the static variable #equipment is getting passed since
<%= #equipment %>
returns
#<Equipment:0xb685ece0>
I am at a loss here. I just did what I did while I was following the railstutorial.org book and I was able to finish the book.
I think your problem lies in your use of the word "equipments". If you open the Rails console run 'equipment'.pluralize you'll see that the plural of "equipment" is "equipment".
So I'd do a search through your project and replace any instance of "equipments" with "equipment" and I'd bet that would fix it.

Resources