How to show model title instead on #<Mymodel:0x000000...> in activeadmin dropdown menus? - ruby

I've created an association where Project has_many Tasks and Task belongs_to Project.
I've created the form in admin/tasks.rb
form do |f|
f.inputs "Details" do
f.input :title
f.input :project
end
f.buttons
end
Now in the edit Task page I hahe a dropdown menu where I can choose the project, but the entry are #<Project:0x00000...>.
How can I customize the entries in the dropdown to show the Project title field instead?
I'm a Rails newbie.

Active admin makes use of formtastic, under the hood formtastic loops through your model searching for a method like name, to_s, value, title, that returns a string.
At the moment you see the data entry itself, if you want formtastic to show the name, make sure you put something like
def name
return self.what_key_you_want_to_use
end
in your Project.rb model.
That should let formtastic show the name action instead of the model .to_s!

This solved it for me:-
In project.rb (Model) to make ActiveAdmin display properly in select dropdown use alias_attribute.
alias_attribute :name, :project_name (or whatever you named the field in your database)

tldr: You can define or alias :to_label on your model to customize the label used:
def to_label
"#{name} - (#{id})"
end
alias_attribute :to_label, :name
The library used by Rails: Formtastic, (or an alternative: Simple Form) uses the collection_label_methods to configure which fields are checked for deriving a label for your model.
Formastic defaults are: "to_label", "display_name", "full_name", "name", "title", "username", "login", "value", "to_s"
Simple Form defaults are: :to_label, :name, :title, :to_s
As most of these fields might already be used in your model, to_label or display_name seems to be the good candidates. I prefer to_label.

You can create a proc like such :
f.input :your_field, member_label: Proc.new { |p| "#{p.name}"}

Related

Rails 4 different validations in one model

I have page with 2 tabs (forms), which used for edit one object.
E.g. its User's info. In first tab there is personal info, in next tab there is billing info.
Each form has own Submit button. How I can validate fields separately. If I understood it right, when I'll try submit form with 4 fields (of 10), it will raise errors, that other fields (6 of 10) wrong.
What is right way to do this?
Create 2 classes to reflect your UI:
class User
has_one :user_info
has_one :billing_info
end
class UserInfo
belongs_to :user
# add your validation
end
class BillingInto
belongs_to :user
# add your validation
end
In your controller:
def edit
#user = User.find(params[:id])
#user_info = #user.build_user_info
#billing_info = #user.build_billing_info
end
Then in your views:
= form_for #user_info do |f|
= form_for #billing_info do |f|
You'll need 2 controllers to handle the POST requests. Should be named UserInfosController and UserBillingInfosController respectively.

How to search the associated model values using 'dusen' gem

In rails 4.0.2, I am trying to use a search plugin called dusen. Using this, I can search same model's values but I am not able to search other(associated) model values. How can I achieve this for single association(has_one / belongs_to) & multi association(has_many) model values?
Reference link:
https://github.com/makandra/dusen
Gem which I am using is dusen (0.4.10)
In controller,
#query = params[:query] || ""
Contact.search(#query)
In model,
belongs_to :city, :class_name=>"City"
search_syntax do
search_by :text do |scope, phrases|
columns = [:name, :contact_number, :email]
scope.where_like(columns => phrases)
end
end
Here, It will search only :name, :contact_number, :email fields, if i try to add below piece of code then it will show an error like undefined method 'search_text' for #<Dusen::Description:0xb438a248>
search_text do
[city.name]
end
Please suggest a solution for this issue.
Assuming your model name is 'User', you'd set it up as follows:
# User.rb
belongs_to :city, :class_name=>"City"
search_syntax do
search_by :text do |scope, phrases|
# namespaced fields to search by.
columns = ["users.name", "users.contact_number", "users.email", "cities.name"]
# specify association to City in scope.
scope.joins(:city).where_like(columns => phrases)
end
end
I hope this helps!

How to validate a mongoid field based on another mongoid field?

I made the switch to nosql and am playing with Mongoid with Sinatra. I'm still new to this, and I"m stumped on this problem.
class Item
field :name, type: String
field :category, type: Moped::BSON::ObjectId # holds _id of the category object
field :cover_type, type: String
validates_presence_of :category
validates_inclusion_of :cover_type, in:["Hardcover", "Softcover"]
end
class Category
field :name
validates_inclusion_of :name, in:["Books", "Movies", "Ebooks"]
end
Imagine a store that sells Books, Movies, and Ebooks and each item sold belongs to one of the three categories. If an Item is listed under the category "Books", then the Item is required to have a field called cover_type. Furthermore, cover_type can only be either "Hardcover" or "Softcover".
When saving an Item, how do I piece together the validate in the Item class for when the Item is in the Book category and therefore requires the presence of the field cover_type, which is also validated as being "Hardcover" or "Softcover"?
If the Item isn't a Book, then cover_type can be null.
Mongoid models inherit ActiveModel validations. You can just write a custom validator method:
class Item
validates :cover_type_must_be_valid, if: :book?
def book?
Category.find(category).name == 'Books'
end
def cover_type_must_be_valid
errors.add(:cover_type, 'must be Hardcover or Softcover') unless %w{Hardcover Softcover}.include? cover_type
end
end
The book? method is unpleasant; why not use belongs_to :category on Item and has_many :items on Category?
EDIT: here’s what book? could look like if you used the has_many and belongs_to:
def book?
category.name == 'Books'
end
Not that different, but you’ll surely be accessing item.category all over your application, I can’t see why you wouldn’t want to make it easier.

how delete record in a polymorphic association using ruby on rails

I am trying to create an activity stream so my model looks like
class CreateFeeds < ActiveRecord::Migration
def change
create_table :feeds do |t|
t.integer :item_id
t.string :item_type
t.integer :user_id
t.timestamps
end
end
end
class Feed < ActiveRecord::Base
belongs_to :user
belongs_to :item, polymorphic: true
end
I have added this to my post controller
feed_item #post
and this to my application controller
def feed_item(item, action = params[:action])
current_user.feeds.create! action: action, item: item
end
I am displaying my post content like
= feed.item.text
my problem is when I call
= link_to "delete", feed.item, method: :delete
I delete the feed item but the reference to the item remain in the database and I get
error: missing template "delete"
unless I add if present?
How can I this reference to an item?
Your code is simply deleting the item, with no impact on the feed. I think you need to either:
Explicitly clear the item_type and item_id references in feed (e.g. by implementing a remove_item method in your Feed controller and model), or
If your domain would allow for it, change your belongs_to association to a has_one association, with corresponding changes to your database. In that case, deleting the item wouldn't require any changes to the associated feed.
As an aside, it's unusual to keep your migration in with your model definition. The migration should really be in a separate file.

Dropdown Filter for Polymorphic association nested_attribute

I'm building an application in which the user can create a Company and add Investments made to that company. The investments can come from two sources user's Funds or companies' Coinvestors. Funds are big deal in the application as the user can do a bunch of stuff in them. The Coinvestors are not that important, but I want to have control over few aspects of so I created a Model just for them. For that I created a Polymorphic association for which I gave the [terrible] name of Investables. I'm running Rails 3.2.15 and Ruby 2.0.0. Models are below:
class Company < ActiveRecord::Base
has_many :investments
accepts_nested_attributes_for :investments
end
class Investment < ActiveRecord::Base
belongs_to :fund, :class_name => "Fund", :foreign_key => 'investable_id'
belongs_to :company, inverse_of: :investments
belongs_to :coinvestor, :class_name => "Coinvestor", :foreign_key => 'investable_id'
end
class Fund < ActiveRecord::Base
has_many :investments, :as => :investable, :dependent => :destroy
end
class Coinvestor < ActiveRecord::Base
has_many :investments, :as => :investable, :dependent => :destroy
end
When editing the company I want to be able to add investments and I want to dynamically add form lines for each new investment. I was able to achieve that following the awesome 165-Edit Multiple Revised.
To make it more complex, I also want to add a Dropdown for choosing the Polymorphic Type so it filters the next Dropdown to show only the names of either the Funds or the Coinvestors.
For that I mostly adapted code from Railscast 88-Dynamic Select Menus(Thanks Ryan!!)
/views/company/edit.html.erb
<%= form_for(#company) do |f| %>
...
<%= f.fields_for :investments do |builder| %>
<%= render 'investment_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Investment", f, :investments, 'table' %>
/views/company/_investment_fields.html.erb
<%= f.select :investable_type , [ "Fund", "Coinvestor" ], {prompt: "Investor Type"} %>
<%= f.grouped_collection_select( :investable_id, investables_to_collection, :investables, :name, :id, :name, {prompt: "Investor"} ) %>
The "investable_to_collection" is a helper I built to aggregate objects from both Funds and Coinvestors models.
module CompaniesHelper
InvestableCollection = Struct.new(:name, :investables)
CollectionItem = Struct.new(:name, :id)
def investables_to_collection
a = Array.new
a << InvestableCollection.new('Fund', Fund.all.map { |item| CollectionItem.new(item.name, item.id )})
a << InvestableCollection.new('Coinvestor', Coinvestor.all.map { |item| CollectionItem.new(item.name, item.id )})
a
end
end
I didn't add any JavaScript yet to filter the dropdown which will be another challenge. But I've got my beautiful view to show data I've already got in the DB. But the dropdown that should show the Fund's or Coinvestor's name is mixing up things: it will show the name of Coinvestor with ID == 1 even if the investment was made by a Fund.
I thought of making one of the models to have a custom ID such as f1, f2, f3 ... instead of 1, 2, 3... so the system wouldn't mix them. But it seems that it would generate other big compatibility issues.
Do you guys have any other idea?
I wouldn't alter the id column (i.e. I wouldn't change it from an auto-incrementing integer), but because you're mixing two lists in the DB into a single list in the UI you will need some way to note which table each item in the UI came from. For that, sure, use whatever ID scheme you want and then use that differentiating ID as the way to lookup the relevant item.
Also, if you're not going to use the auto-incrementing id columns in the UI (for links or whatever), then you could also just remove them and replace them with your custom identification scheme. There's no reason, for example, that you couldn't assign them all a random 8-digit number, ensuring that number is unique across the different types you're going to put into the list, and then using that id in the UI. It seems that the real issue you're running into is how to combine the lists where ids might overlap, and perhaps it may be feasible for you to devise a way to assign a non-overlapping ID.
Another possibility for assigning non-overlapping IDs, without having to come up with your own scheme or checking for uniqueness across multiple tables is to use a UUID for the lookup ID in the UI drop-down.

Resources