How to customize formtastic attribute :as=>:check_boxes - ruby-on-rails-3

my problem is that I try to customize the formatastic view. But before I go into detail, I'll explain my model.
I have 2 objects with a n:m relation Shop and Category
Shop model looks like that:
has_many :shop_categories, :class_name => "ShopCategory", :foreign_key => "shop_id"
has_many :categories, :through => :shop_categories, :source => :categories
Category model looks like that:
has_many :shop_categories, :class_name => "ShopCategory", :foreign_key => "category_id"
has_many :shops, :through => :shop_categories, :source => :shops
And of course my m to n table looks like
belongs_to :shops, :class_name => "Shop", :foreign_key => "shop_id"
belongs_to :categories, :class_name => "Category", :foreign_key => "category_id"
validates :shop_id, :presence => true
validates :category_id, :presence => true
This works fine and the following command in my Shop view will list all elements from categories within checkboxes:
<%= f.input :categories, :as => :check_boxes, :id => 'shop_categories' %>
Here is my problem:
Within categories I have a name for the category and a picture. Now I want to display the picture next to the selectbox.
I also tryed to use <% f.fields_for :categories do |category| %> but rails wont go through all category elements.
Is there a way to handle all Category elements with automatic checked objects?
If you need more information, i will be glad to give all what you need to understand the problem.
Thank you for any hint.

Try overriding custom inputs:
# app/inputs/collection_check_boxes_input.rb
class CollectionCheckBoxesInput < SimpleForm::Inputs::CollectionCheckBoxesInput
# [...]
end

Related

ActiveAdmin customize view for has_many :through

I'm working on a ActiveAdmin app with this models :
User
class User < ActiveRecord::Base
# A User has many roles for interact on a project
has_many :roles, :dependent => :destroy
has_many :projects, :through => :role
end
Role
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
Project
class Project < ActiveRecord::Base
# A project has many roles for interact
has_many :roles, :dependent => :destroy
has_many :users, :through => :role
accepts_nested_attributes_for :roles
end
To add users with a role on each project I make this form :
form do |f|
f.inputs "Details" do # Project's fields
f.input :title
f.input :code
end
f.has_many :roles do |app_f|
app_f.inputs do
if !app_f.object.nil?
app_f.input :_destroy, :as => :boolean, :label => "Destroy?"
end
app_f.input :user
app_f.input :senior_author
end
end
f.buttons
end
My first question is how can I make a with user.firstname + user.lastname. Actually I have something like this :
#<User:0x007fb98a7d6568>
Second question is my Role model is a list of boolean attributes :
:senior_author
:first_author
:viewer
....
Can I make a with that ?
Another solution would be to just define to_s in the model:
def to_s
"#{email} | #{firstname} #{lastname}"
end
No need to set :label_method.
Just add :label_method => lambda:
app_f.input :user, :label_method => lambda{|u| "#{u.email} | #{u.firstname} #{u.lastname}" }
I fix it by adding this method to models/user.rb
# format label for formtastic dropdown menu
def to_label
"#{email} | #{firstname} #{lastname}"
end
And I use it like this :
app_f.input :user, :include_blank => false, :label_method => :to_label

Querying for a relationship in ruby on rails and update results via Ajax

I have a ROR app that has many players, and many proposed games. The games display on a feed and a player can decide to hide them from this feed. The hidden function works like this:
in player.rb:
has_many :hides, :foreign_key=> "hider_id",
:dependent => :destroy
has_many :hidees, :through => :hides
def hidden?(hidee)
hides.find_by_hidee_id(hidee)
end
def hide!(hidee)
hides.create!(:hidee_id => hidee.id)
end
def unhide!(hidee)
hides.find_by_hidee_id(hidee).destroy
end
hides_controller.rb
class HidesController < ApplicationController
def create
#game = Game.find(params[:hide][:hidee_id])
current_profile.hide!(#game)
redirect_to :back
end
def destroy
#game = Hide.find(params[:id]).hidee
current_profile.unhide!(#game)
redirect_to :back
end
end
hide.rb
class Hide < ActiveRecord::Base
attr_accessible :hidee_id
belongs_to :hider, :class_name => "Player"
belongs_to :hidee, :class_name => "Game"
validates :hider_id, :presence => true
validates :hidee_id, :presence => true
end
game.rb
has_many :reverse_hides, :foreign_key => "hidee_id",
:class_name => "Hide",
:dependent => :destroy
has_many :hiders, :through => :reverse_hides
routes.rb
resources :games do
member do
post :publish
post :unpublish
get :view
get :hidees, :hiders
end
I'm trying to do two things: 1. Write a function that would allow me to hide a game from the feed if a relationship between hidden relationship between game and player exits, and 2. write a "show hidden" button that would allow me to return all projects that were "hidden" by the player.
So far with part 1. I have the following code in the view, and while this does the trick in terms of setting up the relationships, it does not "hide" the game from the feed--I'm guessing I would need ajax for that??
- if current_profile.hidden?(game)
= form_for current_profile.hides.find_by_hidee_id(game), :html => { :method => :delete } do |f|
= f.submit "Unhide", :title => "Unhide this game."
- else
= form_for current_profile.hides.build(:hidee_id => game.id) do |f|
= f.hidden_field :hidee_id
= f.submit "Hide", :title => "Hide this game"
Thank you so much for viewing this, I know it's quite long, but I would appreciate any help you could offer. Also, thank you for you time.

Setting up a polymorphic has_many :through relationship

rails g model Article name:string
rails g model Category name:string
rails g model Tag name:string taggable_id:integer taggable_type:string category_id:integer
I have created my models as shown in the preceding code. Articles will be one of many models which can have tags. The category model will contain all categories which may be assigned. The tag model will be a polymorphic join-table which represents tagged relationships.
class Article < ActiveRecord::Base
has_many :tags, :as => :taggable
has_many :categories, :through => :taggable
end
class Category < ActiveRecord::Base
has_many :tags, :as => :taggable
has_many :articles, :through => :taggable
end
class Tag < ActiveRecord::Base
belongs_to :taggable, :polymorphic => true
belongs_to :category
end
I can't seem to get this to work, I can do it non polymorphic, but I must have something wrong with the polymorphic part. Any ideas?
Edit: Still not getting this right:
class Article < ActiveRecord::Base
has_many :taggables, :as => :tag
has_many :categories, :through => :taggables, :source => :tag, :source_type => "Article"
end
class Category < ActiveRecord::Base
has_many :taggables, :as => :tag
has_many :articles, :through => :taggables, :source => :tag, :source_type => "Article"
end
class Tag < ActiveRecord::Base
belongs_to :taggable, :polymorphic => true
belongs_to :category
end
To create a polymorphic has_many :through, you must first create your models. We will use'Article,' 'Category,' and 'Tag' where 'Tag' is the join-model and Article is one of many objects which can be "tagged" with a category.
First you create your 'Article' and 'Category' models. These are basic models which do not need any special attention, just yet:
rails g model Article name:string
rails g model Category name:string
Now, we will create our polymorphic join-table:
rails g model Tag taggable_id:integer taggable_type:string category_id:integer
The join-table joins together two tables, or in our case one table to many others via polymorphic behavior. It does this by storing the ID from two separate tables. This creates a link. Our 'Category' table will always be a 'Category' so we include 'category_id.' The tables it links to vary, so we add an item 'taggable_id' which holds the id of any taggable item. Then, we use 'taggable_type' to complete the link allowing the link to know what it is linked to, such as an article.
Now, we need to set up our models:
class Article < ActiveRecord::Base
has_many :tags, :as => :taggable, :dependent => :destroy
has_many :categories, :through => :tags
end
class Category < ActiveRecord::Base
has_many :tags, :dependent => :destroy
has_many :articles, :through => :tags, :source => :taggable, :source_type => 'Article'
end
class Tag < ActiveRecord::Base
belongs_to :taggable, :polymorphic => true
belongs_to :category
end
After this, setup your database using:
rake db:migrate
That's it! Now, you can setup your database with real data:
Category.create :name => "Food"
Article.create :name => "Picking the right restaurant."
Article.create :name => "The perfect cherry pie!"
Article.create :name => "Foods to avoid when in a hurry!"
Category.create :name => "Kitchen"
Article.create :name => "The buyers guide to great refrigeration units."
Article.create :name => "The best stove for your money."
Category.create :name => "Beverages"
Article.create :name => "How to: Make your own soda."
Article.create :name => "How to: Fermenting fruit."
Now you have a few categories and various articles. They are not categorized using tags, however. So, we will need to do that:
a = Tag.new
a.taggable = Article.find_by_name("Picking the right restaurant.")
a.category = Category.find_by_name("Food")
a.save
You could then repeat this for each, this will link your categories and articles. After doing this you will be able to access each article's categories and each categorie's articles:
Article.first.categories
Category.first.articles
Notes:
1)Whenever you want to delete an item that is linked by a link-model make sure to use "destroy." When you destroy a linked object, it will also destroy the link. This ensures that there are no bad or dead links. This is why we use ':dependent => :destroy'
2)When setting up our 'Article' model, which is one our 'taggable' models, it must be linked using :as. Since in the preceeding example we used 'taggable_type' and 'taggable_id' we use :as => :taggable. This helps rails know how to store the values in the database.
3)When linking categories to articles, we use:
has_many :articles, :through => :tags, :source => :taggable, :source_type => 'Article'
This tells the category model that it should have many :articles through :tags. The source is :taggable, for the same reason as above. The source-type is "Article" because a model will automatically set taggable_type to its own name.
You simply cannot make the join table polymorphic, at least Rails does not support this out of the box. The solution is (taken from Obie's Rails 3 way):
If you really need it, has_many :through is possible with polymorphic associations, but only by specifying exactly what type of polymorphic associations you want. To do so you must use the :source_type option. In most cases you will have to use the :source option, since the association name will not match the interface name used for the polymorphic association:
class User < ActiveRecord::Base
has_many :comments
has_many :commented_timesheets, :through => :comments, :source => :commentable,
:source_type => "Timesheet"
has_many :commented_billable_weeks, :through => :comments, :source => :commentable,
:source_type => "BillableWeek"
It's verbose and the whole scheme loses its elegance if you go this route, but it works:
User.first.commented_timesheets
I hope I helped!

Rails 3 has_many through scope with joins returns unexpected results

I am trying to create scopes to find all Galleries by a specific category type, like "Style". Eventually, they will be chained to filter by multiple category types, but I can't get the first to work.
Here are the models:
Gallery:
has_many :gallery_categories, :class_name => "GalleryCategories", :dependent => :destroy
has_many :categories, :through => gallery_categories
has_many :colors, :through => gallery_categories, :source => :category, :conditions => {:type => "Color"}
has_many :styles, :through => gallery_categories, :source => :category, :conditions => {:type => "Style"}
...and many more types of categories...
Category:
:has_many :gallery_categories
:has_many :galleries, :through => :gallery_categories
GalleryCategories:
:belongs_to :gallery
:belongs_to :category
I am trying to do something like this in Gallery:
:scope :by_style, lambda {|style| joins(:styles).where(:category => {:name => style})}
Then, for example, I run
Gallery.by_style("Contemporary")
And I am returned 181 Galleries when there are only 40 Galleries, and in this example there should only be one returned with the style "Contemporary".
Here is the resulting SQL:
SELECT `galleries`.* FROM `galleries` INNER JOIN `gallery_categories` ON `galleries`.`id` = `gallery_categories`.`gallery_id` INNER JOIN `categories` ON `categories`.`type` = 'Style' WHERE `categories`.`name` = 'Contemporary'
Any ideas? Thanks in advance.

multiple joins using activerecord in rails

I'm building a small twitter style microblogging service where users can follow other users and get a feed of their messages
I have the following models:
class Follow < ActiveRecord::Base
belongs_to :follower, :class_name => "User"
belongs_to :followee, :class_name => "User"
end
class User < ActiveRecord::Base
has_many :follows, :foreign_key => 'follower_id',
:class_name => 'Follow'
has_many :followers, :through => :follows
has_many :followed, :foreign_key => 'followee_id',
:class_name => 'Follow'
has_many :followees, :through => :followed
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user
end
To get a feed for the current user, I want to perform the following SQL query:
SELECT * FROM follows JOIN users JOIN messages WHERE follows.follower_id = current_user.id AND follows.followee_id = users.id AND users.id = messages.user_id;
What is the correct ActiveRecord way of doing this?
Not sure what you're looking for, but here is my suggestion:
I assume that you have other purposes for that Follow class, otherwise I don't see the purpose of it.
The "correct way" (i.e. my completely subjective way) to do it would actually be something like this:
class User < ActiveRecord::Base
has_and_belongs_to_many :followers, :foreign_key => 'followed_id',
:class_name => 'User', :association_foreign_key => 'follower_id',
:include => [:messages]
has_and_belongs_to_many :follows, :foreign_key => 'follower_id',
:class_name => 'User', :association_foreign_key => 'followed_id'
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user
end
Then create the following table:
create_table :users_users, :id => false do |t|
t.integer :followed_id
t.integer :follower_id
end
And you're set:
followed = User.find :first
follower = User.find :last
followed.followers << follower
followed.followers.first.messages
followed.followers.first.followers.first.messages # etc...
But from what I make it, you want to show all the messages from all the followers at the same time.
This should be possible to achieve by adding
has_and_belongs_to_many :followed_messages, :foreign_key => 'follower_id',
:class_name => 'Message', :association_foreign_key => 'followed_id'
to the User class, but I don't know how correct that way would be. Or it might be possible to achieve with association extensions but there I can't really give any examples.
Update:
By changing the :class_name, it will associate it with the Message.id, didn't think about that so it will not be correct in this way.
So the only "nice" option is to go through the User class like in the first example.
The only other options I can see is either the association extensions (which I can't give you an example for) or perhaps using a finder statement.
has_many :followed_messages, :class_name => 'Message',
:finder_sql => 'select * from messages where user_id in(select followed_id from users_users where follower_id = #{id})'
You probably have to customize that sql statement to get everything to work, but at least you should get the picture :)
Keijro's arrangement would work better, though if you need the Follow table, then you can execute the SQL query you specified as follows:
Follow.all(:joins => { :messages, :users }, :conditions => { "follows.follower_id" => current_user.id, "follows.followee_id" => "users.id", "users.id" => "messages.user_id"} )