I'm working in Rails 2, and my model look like this:
class Site < ActiveRecord::Base
has_many :contacts
def primary_contact
Contact.find :first, :conditions => {:site_id => self,
:primary_contact => true}
end
def primary_contact= new_primary_contact
contact = Contact.find(new_primary_contact)
contact.primary_contact = true
contact.save
end
end
Note that the :primary_contact virtual attribute is initialized in the model, so the default value should be present.
The form for #site in my view contains this input:
<%= form.input :primary_contact, :as => :check_boxes, :collection => (Contact.find(:all, :conditions => {:site_id => #site.id}, :order => "first_name ASC")), :label => false, :include_blank => false %>
This gives me a list of checkboxes, with the correct default checkbox already checked (ie the primary contact for that site is selected). However, I want this in the form of radio buttons or a select drop-down, and in those two cases, just by changing :as => :check_boxes to :as => :select or :as => :radio, the default isn't selected.
I also tried specifying the collection as just :collection => #site.contacts, but same thing.
Any idea what I'm doing wrong?
Which version of Formtastic? Sounds like it could be a bug. If you can still repeat after upgrading to Formtastic 1.2.4, please file an issue on Github.
Related
f.has_many :offers,heading: 'Offers' do |item|
item.input :quantity
item.input :offer_type_id, :prompt => 'Select Offer Type', :as => :select, :collection => OfferType.all.map{|m| [m.title, m.id]}
item.input :_destroy, :as => :boolean
end
It works fine and has_many association created. I want that the button for adding associated data automatically clicked or open when I load page.
Add new Offer
Instead that user click on it for first associated data it automatically clicked
In AA controller block you need yo build offer - it will add the offer's fields to the form:
controller do
def new
super do
resource.offers.build
end
end
end
I need to create a form in my rails3 application that, when saved, will validate the fields and then submit them. I need a row for each field essentially.
The reason for this is that each 'user' has multiple attributes. For example:
User-Password
Expiration
Access-Group
Have tried a nested form but that doesn't really work for me.
In my console, this works pretty well for me:
user = Array.new
user << {:username => "jenny", :attribute_name => "User-Password", :value => "123"}
user << {:username => "jenny", :attribute_name => "Expiration", :value => "123"}
user << {:username => "jenny", :attribute_name => "Access-Group", :value => "123"}
User.create(user)
That inserts a number of rows, each with the same username but different attribute names and values. Perfect.
My problem is, how do I do this using a single form?? Initially I had a parent model and a nested form but I can't figure it out.
This should actually be pretty straightforward nested form. Let us assume
class User
has_many :attributes
accepts_nested_attributes_for :attributes, :reject_if => :all_blank, :allow_destroy => true
end
class Attribute
belongs_to :user
end
and an Attribute has an attribute_name, a value and a user_id.
Then your form, using haml, simple_form and cocoon would look like
= simple_form_for #user do
= f.input :name
#attributes
= f.simple_fields_for :attributes do |attribute|
= render 'attribute_fields', :f => attribute
.links
= link_to_add_association 'add new attribute', f, :attributes
and you add a partial called _attribute_fields.html.haml
.nested-fields
= f.input :attribute_name
= f.input :value
= link_to_remove_association "remove attribute", f
If the attributes are fixed, you could easily change the input for attribute_name to
= f.input :attribute_name, :as => :select, :collection => {'User-Password', 'Expiration', 'Access-Group' }
If you want to read more about different types of nested forms, I have written a blogpost about it in greater detail.
[EDIT] Adding server-side validation to Attribute model:
Inside class Attribute you need to add:
validate :check_valid_values
def check_valid_values
if attribute_name == 'Expiration'
errors.add(:value, "Must be a valid date for Expiration") unless value.is_a_valid_date?
end
end
Note that the method is_a_valid_date? does not exist, this is just to provide a small example. In this validation method you would then add all the possible attribute-value combinations with their validation.
Hope this helps.
I am using Ruby on Rails 3.0.7 and I have a problem on an associated model validation for an updating controller action. I am using an "has_many :through" association so that I can handle user-category relationships.
In the User model I have:
has_many :user_category_relationships,
:autosave => true,
:dependent => :destroy
has_many :user_categories,
:through => :user_category_relationships,
:source => :user_category,
:dependent => :destroy
In the _form view file I have:
<% #current_user.user_categories.each do |user_category| %>
<%= check_box_tag :user_category_ids, user_category.id, #user.user_categories.include?(user_category), :name => 'user_relationships[user_category_ids][]' %>
<%= label_tag "user_category_#{user_category.id}", user_category.name %>
<% end %>
In the UserCategoryRelationship model I have:
belongs_to :users
belongs_to :categories
# Validation
validates :name_id,
:presence => true,
:uniqueness => {
:scope => [:created_by_user_id, :category_id]
}
validates :category_id,
:presence => true,
:uniqueness => {
:scope => [:created_by_user_id, :name_id]
}
validates :created_by_user_id,
:presence => true,
:uniqueness => {
:scope => [:category_id, :name_id]
}
In the UsersController I have:
def create
...
# `params[:user_relationships][:user_category_ids]` used below are id values
# related to user-category relationships.
unless params[:user_relationships][:user_category_ids]
# Set default user category if not selected.
#user.user_category_relationships.build(
:category_id => '1',
:created_by_user_id => #current_user.id,
:name_id => #name.id
)
else
params[:user_relationships][:user_category_ids].each { |user_category_id|
#user.user_category_relationships.build(
:category_id => user_category_id,
:created_by_user_id => #current_user.id,
:name_id => #name.id
)
}
end
if #user.save
...
end
end
def update
...
# Note: The following code is equal to that in the controller 'create'
# action. However here is my problem because validation (read after
# for more information about).
unless params[:user_relationships][:user_category_ids]
# Set default user category if not selected.
#user.user_category_relationships.build(
:category_id => '1',
:created_by_user_id => #current_user.id,
:name_id => #name.id
)
else
params[:user_relationships][:user_category_ids].each { |user_category_id|
#user.user_category_relationships.build(
:category_id => user_category_id,
:created_by_user_id => #current_user.id,
:name_id => #name.id
)
}
end
if #user.update_attributes(params[:user])
...
end
end
The above code works except for the update action: when I try to run that I get always the same error, as well.
# Validation errors on updating the 'user_category_relationships' associated model
:"user_category_relationships.category_id" =>["has already been taken"]
:"user_category_relationships.name_id" =>["has already been taken"]
:"user_category_relationships.created_by_user_id" =>["has already been taken"]
What I would like to do, since I am not using the "RoR magical\automatic way" at all (that is, I don't use the collection_singular_ids method - see also this and this), is to make properly work the update controller action so that I can still use the "automatic" creation of user-category relationships (triggered on save and update_attributes(...) methods) but avoiding to generate above validation errors (that is, create valid data in the database table). How can I do? What do you advice about this issue?
P.S.: Where I am in trouble is in the update action, precisely figuring out how to "choose"\"filter" and "coding" records to update, to create and to delete in the database having params[:user_relationships][:user_category_ids] as input data.
I would like to assign two different "types" of tags (sector categories and free tagging) to a Company model using acts_as_taggable_on. NB: I'm new to RoR!
This is easy to do if just using standard text input fields, but I would like to use check-boxes on one type (a fixed sector category tag that is predefined), and then allow the user to add comma separated tags in an input field.
I have played around with this problem in various ways,... one inspired by this question...but I cannot get it to work
Here is what I have so far:
# models/company.rb
class Company ...
acts_as_taggable_on :tags, :sectors
has_many :taggings,
:as => :taggable,
:include => :tag,
:class_name => "ActsAsTaggableOn::Tagging",
:conditions => { :taggable_type => "Company" }
has_many :sector_tags,
:through => :taggings,
:source => :tag,
:class_name => "ActsAsTaggableOn::Tag",
:conditions => {:context => "sectors"}
end
in the form (using simple_form gem) I have...
# views/companies/_form.html.haml
= simple_form_for #company do |f|
= f.input :name
= f.association :sector_tags, :as => :check_boxes, :hint => "Please click all that apply"
= f.input :tag_list
= f.button :submit, "Add company"
And in my Company controller I have
# controllers/companies_controller.rb
def create
#company = current_user.companies.build(params[:company])
if #company.save
...
end
But this causes a validation error:
ActiveRecord::RecordInvalid in CompaniesController#create
Validation failed: Context can't be blank
Can anyone hint at how I can do this right?
A related question is if this is a good way to do it at all? Would I be better off just using a Category model for assigning sector tags through a joint model?
Thanks!
Well, I solved my problem. And it turned out to be quite simple. Alas, I ended up creating a separate Sector model through a joint "sectorizations" table. But if anyone is interested, I just wanted to update on what I did in the case above...
In my company model
# models/company.rb
class Company ...
acts_as_taggable_on :tags, :sectors
...
end
in the form
# views/companies/_form.html.haml
= simple_form_for #company do |f|
= f.input :name
= f.input :sector_list, :as => :check_boxes, :collection => #sectors, :hint => "Please check all that apply"
= f.input :tag_list
= f.button :submit, "Add company"
and in the company controller (create)
# controllers/company_controllers.rb
def new
#company = Company.new
#sectors = get_sectors
end
def get_sectors
sectors = []
for sector in Company.sector_counts
sectors << sector['name']
end
return sectors
end
It seems that act_as_taggable_on uses single table inheritance, so you actually don't need to create any additional tables. However you do need to follow their convention (that they never stated) as follows:
//add to model
attr_accessible :yourfieldname_list
acts_as_taggable_on :yourfieldname
//view
<%= f.text_field :yourfieldname_list %>
I installed Sphinx and Thinking Sphinx for ruby on rails 2.3.2.
When I search without conditions search works ok. Now, what I'd like to do is filter by tags, so, as I'm using the acts_as_taggable_on plugin, my Announcement model looks like this:
class Announcement < ActiveRecord::Base
acts_as_taggable_on :tags,:category
define_index do
indexes title, :as => :title, :sortable => true
indexes description, :as => :description, :sortable => true
indexes tags.name, :as => :tags
indexes category.name, :as => :category
has category(:id), :as => :category_ids
has tags(:id), :as => :tag_ids
end
For some reason, when I run the following command, it will bring just one announcement, that has nothing to do with what I expect. I've got many announcements, so I expected a lot of results instead.
Announcement.search params[:announcement][:search].to_s, :with => {:tag_ids => 1}, :page => params[:page], :per_page => 10
I guess something is wrong, and it's not searching correctly.
Can anyone give my a clue of what's going on?
Thanks,
Brian
Thinking Sphinx relies on associations in model. In common situations you only have to put index definition below your associations.
With acts_as_taggable_on plug-in you don't have tag-related associations in model file and when you write
indexes tags.name, :as => :tags
TS interprets it like:
CAST(`announcements`.`name` AS CHAR) AS `tags`
(look at sql_query in development.sphinx.conf, in my case).
I suppose that you have attribute name in model Announcement and don't run into error when rebuild index.
But we expect:
CAST(GROUP_CONCAT(DISTINCT IFNULL(`tags`.`name`, '0') SEPARATOR ' ') AS CHAR) AS `tags`
and:
LEFT OUTER JOIN `taggings` ON (`announcements`.`id` = `taggings`.`taggable_id`)
LEFT OUTER JOIN `tags` ON (`tags`.`id` = `taggings`.`tag_id`) AND taggings.taggable_type = 'Announcement'
To get things working just add tag-related associations in your model before you rebuild index:
class Announcement < ActiveRecord::Base
acts_as_taggable_on :tags,:category
has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging",
:conditions => "taggings.taggable_type = 'Announcement'"
#for context-dependent tags:
has_many :category_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag",
:conditions => "taggings.context = 'categories'"
In define_index method:
indexes category_tags(:name), :as => :tags
has category_tags(:id), :as => :tag_ids, :facet => true
In controller:
#announcement_facets = Announcement.facets params[:search], :with => {:tag_ids => [...]}
#announcements = #announcement_facets.for.paginate( :page => params[:page], :per_page => 10 )
I found that simply defining the index thus:
Class Thing < ActiveRecord::Base
acts_as_taggable
define_index do
..other indexing...
indexes taggings.tag.name, :as => :tags
end
end
worked fine.
One possibility is that you need to declare the type for tag_ids as :multi because TS can get confused (I just discovered this here http://groups.google.com/group/thinking-sphinx/browse_thread/thread/9bd4572398f35712/14d4c1503f5959a9?lnk=gst&q=yanowitz#14d4c1503f5959a9).
But why not use the tag names to search? E.g.,
Announcement.search params[:announcement][:search].to_s, :conditions => {:tags => "my_tag"}, :page => params[:page], :per_page => 10
Or, if you need to search for multiple tags:
Announcement.search( "#{params[:announcement][:search].to_s} (#tags my_tag | #tags your_tag)", :page => params[:page], :per_page => 10 )
(as aside, you may want to sanitize/remove sphinx-control-characters from the user-provided query before using it).
For debugging, I would go into console and strip down your query as much as possible (eliminate pagination arguments, even the query (just do ""), etc.).