belongs_to association and formtastic - ruby-on-rails-3

I have a model Product which has a belongs_to association with another model Type. In the product's form, I'm using formtastic to display a select tag with all the types available in the database, like this:
<%= f.input :type %>
The select is showing up OK, but each option of it is an object instance of the Type model as a string, for example:
#<Type:0x00eff180c85c8>
Instead of that, I'd like to display the 'title' attribute of it, like:
Electronic
Domestic
...
Any ideas?

Try the member_label option, it sounds like what you want to do:
<%= f.input :type, :member_label => :title %>
The documentation has more examples.

Simply add this in your model
def name
return self.title
end

Related

Override a form field value in rails form

Note: I was overthinking things when I originally asked this question. The accepted answer is correct for the examples I gave - i.e. you can just pass :value to text_field, however I'd actually been having problems with date_select, which doesn't have a facility to override the value set.
As a result this has now been updated in Rails, so you can set :selected => a_date, and it will work as expected. This will be in Rails 4.
I have a model that can inherit its value from a parent model. It works something like this:
class User < ActiveRecord::Base
attr_accessible :field_name
belongs_to :company
def field_name
if self['field_name'].nil?
company['field_name']
else
self['field_name']
end
end
end
class Company < ActiveRecord::Base
attr_accessible :field_name
end
I then have a form to edit the User, but of course, if the User value is nil, then it populates the form with the value from Company, which is not what I want.
I would like to be able to override the value of the form field, so that if the User value is nil, then the value is empty.
Attempt 1
Ideally I'd be able to do:
<%= form_for #user do |f| %>
<%= f.text_field :field_name, #user['field_name'] %>
<% end %>
But that doesn't work, there doesn't seem to be a mechanism for providing an override value.
Attempt 2
So I thought about creating a second getter/setter:
def field_name_uninherited
self['field_name']
end
def field_name_uninherited=(value)
self['field_name']=value
end
Now I can use <%= f.text_field :field_name_uninherited %> and it works as expected - great! Except: when field_name is a date, or other type using multiparameter attributes, it results in this error:
1 error(s) on assignment of multiparameter attributes
I believe this is because it doesn't know that this is a date field, as it infers this from the database, and this field (with _uninherited suffix) is not in the database.
So I need some way to mark my additional method as the same type as the original database field.
A further note, the above examples (using field_name) are a simplified version. I'm actually using https://github.com/colinbm/inherits_values_from to handle the inheritance, but I don't think this is important to the question.
Obviously if there's a better way to accomplish the same goal, then I'm all ears.
So when it comes to displaying the value you for a user you want it to behave a bit differently?
What I'd do is use the :value option with your form field. That way you get to set the value like normal but choose what you want displayed in the form field.
<%= f.text_field :company, :value => user.field_name_uninherited %>
For what I understand, you want the user to put the field data and only if it's nil, populate that value with the parent (company) model. It seems to me before_save works perfectly, because it is called (as it name proposes) just before the save method is called on an ActiveRecord object.
Thus you can write this kind of callback:
class User < ActiveRecord::Base
attr_accessible :field_name
before_save :override_field
private
def override_field
if self.field_name.nil?
self.field_name = company.field_name
end
end
This way, you'll be only overriding the value if it's nil at the moment of saving, leaving that form field empty at the moment of creating a new element. Hope this works!

Accessing attributes from different associated models rails 3

I am looking to get a better understanding of Active Model/Record relationships and how to call attributes dependent upon where the attributes are located (models) and where I am calling them. So for example I can access the attribute dish_name from within the recipe controller like so
def all_recipes
#recipes = Recipe.all
end
In the view
<% #recipes.each do |r| %>
<%= r.dish_name %>
<% end %>
Now say i want to access a recipe attribute from within my controller called worldrecipes and i have just written a method that returns all recipes with the same country. a country has many recipes as a relation
So my method is
def self.top_countries
joins(:recipes).
select('countries.*, count(*) AS recipes_count').
group('countries.id').
order('recipes_count DESC')
end
My controller
#worldrecipes = Country.where(:name => params[:name])
and view
<% #worldrecipes.each do |r| %>
<%= r.name %>
<% end %>
so accessing the country name attribute is easy as its in the country model and thats where my query results are being returned from (I think)...My question is how do i access the dish_name attribute from my recipe model to that links to the country name
Hope that makes sense, does anyone have a guide on how to work this out or some golden rules for this
Thank you
I think what you need is:
#country=Country.where(:name=>params[:name]).first
#worldrecipes=#country.recipes
And in the view:
<% #worldrecipes.each do |r| %>
<%= r.dish_name %>
<% end %>
This would print the dish names of the recipes of the country with name provided by params[:name]
EDIT:
Ok Let me clear this up for you :)
Your model relationship is setup such that each country has many recipes. i.e a country has many recipes.
So you have,
has_many :recipes
in country.rb and
belongs_to :country
in recipe.rb
Now when you want to access all the recipes belonging to a country, what you do is, you call country_record.recipes (country_record being the object of the country record you need).
And when you call,
Country.where(:name=>params[:name])
What you actually get is the active record object representing the COUNTRY itself and not the recipes of the country and that is why Italy was printed.
Hope this helped you.
For starters you want to make sure you have the association setup in your models:
country.rb
class Country < ActiveRecord::Base
has_many :recipes
end
recipe.rb
class Recipe < ActiveRecord::Base
belongs_to :country
end
If you haven't already done so, add a foreign_key attribute to your recipe model by running the following migration:
rails g migration add_country_id_to_recipe country_id:integer
Now that your associations are in place you can easily query for a countries respective recipes. In your controller:
#worldrecipes = Country.where(:name => params[:name])
Then in your view:
<% #worldrecipes.each do |c| %>
<% c.recipes.each do |r| %>
<%= r.dish_name %>
<% end %>
<% end %>
In regards to 'golden rules' I highly recommend you check out Association Basics. This is the go-to place for an overview of what you can do with associations.

Rails syntax Passing POST parameters from a form to a controller

I'm new to Rails (and fairly new to programming in general) and I am building a web app for myself as a way to learn. Right now I am modifying scaffolded forms and such.
My question is with the "create" method in one of my controllers. There are two entities I am concerned with: the User table and the Habit table. I created a dropdown box in the _form partial for the Habit views to allow a person to select a user from a list of all available when creating a habit as below
<%= collection_select :user, :id, #users, :id, :first_name %>
The habit controller, of course, has
def new
#users = User.all
...
end
This works fine, and when the form submits it posts two hashes of parameters :habit and :user. Now, when I want to process the form input in the create method, I'm not sure how to use the syntax correctly and assign the user_id to the newly create habit. What I WANT to do is something like this
def create
#habit = Habit.new(params[:habit], params[:user])
end
This, of course, is improper syntax.
def create
#habit = Habit.new(params[:habit])
end
assigns the params from the :habit hash correctly, but then the user_id is left unset.
What works is the following, but the code is very lengthy, assigning each value manually.
def create
#habit = Habit.new(:user_id => params[:user][:id],
:description => params[:habit][:description],
:habit_method => params[:habit][:habit_method],
:time_reqd => params[:habit][:time_reqd],
:will_reqd => params[:habit][:will_reqd],
:active => params[:habit][:active])
end
So my question is, when dealing with a form that posts data in multiple hashes, what is the proper way to pass those parameters into some method in a controller?
So my question is, when dealing with a form that posts data in multiple hashes, what is the proper way to pass those parameters into some method in a controller?
Instead of saying Habit.new( <lots of stuff> ), just use Habit.new(params[:habit]). Rails will try to assign each key in the hash (in this case, the params[:habit] hash's keys) to a matching value on the object.
Thus, if params[:habit] has a :description key, it will be assigned to a field called description on your model. This is called mass assignment and is quite handy.
Now you can just do:
#habit = Habit.new(params[:habit])
#habit.user_id = params[:user][:id]
You may want to read the RoR Getting Started Guide, like this section, for more similarly handy features of Rails.
Change
<%= collection_select  :user, :id, #users, :id, :first_name %>
To
<%= collection_select  :habit, :user_id, #users, :id, :first_name %>
The existing scaffold code should just work after that
Alternate
<%= f.select :user_id, #users, :id, :first_name %>

How to implement multiple selection on Rails 3

I have an index where I'm showing a list of documents. I would like to implement a multiple select in order to do different actions to the documents the user has selected
I have created a
<%= check_box_tag 'id', 'document.id %>
for each document, inside a form_tag
But if I select multiple checkboxes, the params that are passed to the action are overwrited and I'm just receiving the id of the last checkbox I've selected in the id param.
¿Anyone knows how to implement multiple select?¿Any other approach?
I'm running Rails 3 and Ruby 1.8.7
Thanks in advance
You need to set :multiple => true
<%= check_box_tag 'id', document.id, :multitple => true %>
This will give you results in form of an array in params[:id]
Minor correction (plural):
<%= check_box_tag 'ids[]', document.id %>
ensure your model is properly set for attr_accessible something like :document_ids

Multiple models, one form in rails. Want to create parent while creating the nested model object in a form

I want to update multiple models with one form in rails. I have looked at Railscasts #196 and many nested model examples but can't get them to work. The difference is I want to create a record in the parent model in a form for the child model.
I have these 3 models:
User Model
has_many :products
has_many :stores
Product Model
belongs_to :user
belongs_to :store
accepts_nested_attributes_for :store
Store Model
has_many: products
I have a form where a user can enter a product in. I want it to have a field where they can enter the store as well. This entry will create a record in the store model as well as product model with the store_id stored in the store model.
Form
<%= form_for #product, :html => { :multipart => true } do |f| %>
<%= f.text_field :product_name %>
<% f.fields_for :store do |store|%>
<%= store.text_area :store_name %>
<%end%>
<% end %>
Controller
#product = Product.new
#product.store.build
This code results in the following error :
undefined method `build' for nil:NilClass
I just want to be able to create a new store entry as they enter the product. (if it is a duplicate entry I will not allow it, but I will handle that elsewhere). Any suggestions?
accepts_nested_attributes_for
Only works for the one to one and one to many relationships, where you have the primary model is the main parent..
You would use it in the the User model for products and/or stores. However it looks like you want to create a new store when they enter a product in if the store doesn't exist right?
Since it appears your store is just a field or two I would just add the store in the controller using the fields for it..