I'm using active admin with ActiveRecord scopes. However, I'm having an issue with adding the scopes.
Running ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux] and
Rails 4.2.5.1
#app/model/accounts.rb
class Account < ActiveRecord::Base
searchkick
belongs_to :program
belongs_to :insurance
has_many :notes
scope :program_name, -> (program) {where(program_name: adult) }
validates :first_name, :last_name, :address, :phone, presence: true
validates :phone, format: { with: /\A\d{3} \d{3}-\d{4}\z/,
message: "must be in the format 123 456-7890" }
end
I want to be able to us this in app/admin/account.rb
#app/admin/account.rb
ActiveAdmin.register Account do
menu :priority => 2
permit_params :first_name, :last_name, :return_client, :program_id, :insurance_id, :address, :phone
index do
column :first_name
column :last_name
column :address
column :phone
column :created_at
column :return_client
column :program
column :insurance
actions
end
scope :all, :default => true
scope :adult, default: true do |accounts|
accounts.program_name('adult')
end
end
I tired using it with and without block. I want the total count of "programs" in that scope as an end result.
You can't have two default scopes and the scope :all is unnecessary so remove it.
You have this scope which looks fine
scope :program_name, -> (program) {where(program_name: adult) }
and you say that
I want to be able to us this in app/admin/account.rb
but you aren't actually using it. You are instead trying to use
scope :adult, default: true do |accounts|
accounts.program_name('adult')
end
So just add it
scope :program_name
But your question seems to be loaded with something else you're trying to do
I want the total count of "programs" in that scope as an end result.
And in that ^ sense, I think you may be misunderstanding how and what scopes are actually used for.
Related
I am trying to go table-less with activerecord-tableless. The main reason to use it is for the associations. Here(in the github documentation) it tells you how to simply work with one model but doesn't say anything about associations.
For example: I have a User and Category model. Each User belongs to a Category.
This is my User model
class User < ActiveRecord::Base
has_no_table
belongs_to :category
column :id, :integer
column :name, :string
column :email, :string
column :password, :string
column :created_at, :string
column :updated_at, :string
column :category_id, :integer
validates :name, :email, :password, presence: true
validates_length_of :password, minimum: 8
end
Now, in the form, I have to get all the categories to select from like this
<%= f.collection_select(:category_id, Category.all, :id, :title) %>
From where, Category.all can retrieve its content. Do I have to override it?
Also, suppose I have a User object and I need to find it's Category object(if I have a category id), then will 'find' work?
If everything has to be overridden, then what is the use of activerecord-tableless.
I am not able to find any documentation or tutorials regarding this. Please help.
PS: I have tried ActiveModel as well but they do not support associations.
PPS: Rails 4.1.1 and Ruby 1.9.3 is being used.
My search working fine.
But I have to type "1" or "2" to get results of "roommate" or "sublet".
Model has a column called category_id which is an integer.
Model Category has column :name which is a string.
Thus, I have category_id 1 is having "roommate" and 2 is "sublet"
below is my Housing model:
class Housing < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
belongs_to :user
belongs_to :category
validates :title, :presence => true
validates :category_id, :presence => true
validates :created_at, :presence => false
validates :user_email, :presence => true
validates :description, :presence => false
validates_length_of :title, :maximum => 30
def self.search(query)
__elasticsearch__.search(
{
query: {
# multi_match: {
simple_query_string: {
query: query,
fields: ['title^10', 'category_id']
}
}
}
)
end
end
How can I fix fields: ['title^10', 'category_id'] So user can search "roommate" instead of must search integer "1" to get result of roommate ?
I tried fields: ['title^10', 'category.name'] but not working.
fields: ['title^10', 'category.name'] won't work unless you have correct mapping defined. Elasticsearch doesn't know about your associations. ES is a document store and searches for records using it's own document store. So unless you add your category name to the document stored in ES, you won't be able to search it.
TL;DR
Define a mapping. Example:
mapping dynamic: 'strict' do
indexes :category do
indexes :name
end
indexes :title
end
Here category will now be stored as nested object inside your index and hence is searchable using category.name
I want to map 2 columns of the same model (dev_status and test_planning_status) to another model's column (Status.name) and in the UserStory form I want to have a dropdown with values from Status table
I have tried something like this but unable to figure out
Status model is like this
class Status < ActiveRecord::Base
has_many :dev_status, :class_name => 'UserStory', :foreign_key => 'dev_status_id'
has_many :test_planning_status, :class_name => 'UserStory', :foreign_key => 'test_planning_status_id'
end
Currently I have this in models/UserStory
class UserStory < ActiveRecord::Base
validates :us_number, presence: true
validates :team_id, presence: true
validates :dev_status, presence:true
validates :test_status, presence:true
belongs_to :team
CreateUserStories migration is
class CreateUserStories < ActiveRecord::Migration
def change
create_table :user_stories do |t|
t.string :us_number
t.references :team
t.string :dev_status
t.string :test_planning_status
t.integer :tc_count
t.timestamps null: false
end
add_foreign_key :user_stories, :pod
end
My UserStoryController params is
def user_story_params
params.require(:user_story).permit(:us_number, :team_id, :dev_status, :test_planning_status)
end
UserStory _form is
<%= f.label :dev_status,'Dev Status' %>
<%= f.select :status, Status.all.map {|u|[u.status, u.id]},
{include_blank: true} %>
<%= f.label :test_planning_status, 'Test Planning Status' %>
<%= f.select :status, Status.all.map {|u|[u.status, u.id]},
{include_blank: true} %>
The goal should be to call UserStory.dev_status.name to get the dev_status name, and UserStory.test_planning_status.name to get the test_planning_status name.
Your migration should be creating columns dev_status_id (not dev_status) and test_planning_status_id (not test_planning_status).
Use t.references or t.belongs_to in your future migrations.
Above columns should be integers, not strings.
You need to specify belongs_to on the UserStory object for your status fields.
belongs_to :dev_status, class_name: 'Status'
belongs_to :test_planning_status, class_name: 'Status'
Change
validates :test_status, presence:true
to
validates :test_planning_status, presence:true
The two f.select :status in your form need to be changed to f.select :test_planning_status and f.select :dev_status
That should get you pointed in the right direction. Hope it helps!
This sounds like a standard has_many relationship::
class Status < ActiveRecord::Base
# columns id | name | value | other | information | created_at | updated_at
has_many :user_stories
end
class UserStory < ActiveRecord::Base
# columns id | title | value | dev_status_id | test_planner_status | created_at | updated_at
belongs_to :dev_status, class_name: :status
belongs_to :test_planning_status, class_name: :status
end
This would give you the ability to access the following:
#app/controllers/statuses_controller.rb
class UserStoriesController < ActionController::Base
def show
#story = UserStory.find params[:id]
##story.dev_status = gives you dev's details, with status value from Status table
end
end
If you wanted to avoid the law of demeter (IE only have one point to access your data), you'll want to use the delegate method:
#app/models/user_story.rb
Class UserStory < ActiveRecord::Base
delegate :name to: :dev_status, prefix: true
# this will allow you to call #user.dev_status_name
end
If you then wanted to have statuses changed, you'll be able to use the collection_select helper to get it working with the Status objects:
#app/views/user_stories/edit.html.erb
...
<%= f.collection_select :dev_status_id, Status.all, :id, :name, prompt: true %>
<%= f.collection_select :test_planner_status, Status.all, :id, :name, prompt: true %>
--
ActiveRecord
You must remember that models are built, they are just classes. Rails uses an ORM (ActiveRecord) to pull data to populate these classes.
Many people become confused about how models fit into the Rails ecosystem. A model is made of "attributes", which you have to populate, either manually or through the Rails ORM API. IE your User model could have the following:
#app/models/user.rb
class User < ActiveRecord::Base
def will_you_marry_me?
"no"
end
end
#app/views/application.html.erb
Will the user marry?
<%= #user.will_you_marry_me? %>
When you talk about "mapping" columns, what you're really asking is how to call a different table's data to attributes in your model class. For example, if you have User class, how to populate #user.birthday with data from profiles table etc.
The answer to that is to use the relational structure of ActiveRecord. Relational databases simply work with foreign_keys to load data from other tables. For example, you could have profiles table with user_id to get information about a specific user (see the image above).
ActiveRecord makes the process of loading "other table" data very simple. By using the relationships in the API, you can populate data with the likes of has_many etc.
I just changed my DB from mysql to postgres and I'm getting the following error:
ActionView::Template::Error (PG::Error: ERROR: operator does not exist: character varying = integer
LINE 1: ...ELECT COUNT(*) FROM "agents" WHERE "agents"."client_id" = 1
when doing
client.agents.count
I have a Data is structured as follows: Clients have several Agents, and can only add more Agents if agents.count < X, so I'm using something like client.agents.count to retrieve this value and compare, but I'm getting that error. Do I need to use manual sql to get this done? Or am I missing something stupid?
Thank you for your comments
MODEL INFO
class Agent < User
belongs_to :client
attr_accessible :client_id
validates :client_id, presence: true
end
class Client < User
attr_accessible :appId, :expire_date, :legacy, :url, :plan_id, :chat_window_color, :chat_head_color, :chat_box_container_color, :chat_box_color, :tab_message, :greeting, :please_wait_message, :send_message_button, :comments_label, :offline_message
belongs_to :plan
has_many :agents, :dependent => :destroy
has_secure_password
after_initialize :init
#omited validations
private
#BEGIN PRIVATE METHODS
end
Both inherit from user
class User < ActiveRecord::Base
self.abstract_class = true
attr_accessible :email, :name, :password, :password_confirmation
attr_accessor :updating_password
has_secure_password
before_save { self.email.downcase! }
#the controller must set updating_password to FALSE to avoid validation
def should_update_password?
updating_password || new_record?
end
end
So I found the issue, the column client_id is a varchar and mysql allowed this but postgres complained about the different datatypes. Got a mgiration working by doing something like this:
def up
rename_column :agents, :client_id, :client_id_old
add_column :agents, :client_id, :integer
Agent.reset_column_information
Agent.find_each { |c| c.update_attribute(:client_id, c.client_id_old) }
remove_column :agents, :client_id_old
end
From this link How do I change column type in Heroku?.
To avoid the issues when changing datatypes in postgres directly with change_column. Hope this helps someone else
I have a model as follows:
class EntityTag < ActiveRecord::Base
attr_protected :user_id, :post_id, :entity_id
belongs_to :user
belongs_to :post
belongs_to :entity
validates :user_id, :presence => true
validates :entity_id, :presence => true
validates :post_id, :presence => true
end
I want to guard against multiple rows which have the same combination of user_id, entity_id, and post_id (e.g. a unique ID for a row is all three of those values).
What's the easiest way I can communicate that to ActiveRecord?
As #dhruvg mentioned:
validates_uniqueness_of :user_id, :scope => [:entity_id, :post_id]
Do note that uniqueness validation on model level does NOT guarantee uniqueness in the DB. To have that, you should put a unique index on your table.
Add the following to your migrations.
add_index :entity_tags, [:user_id, :post_id, :entity_id], :unique => true
I would check for this in the create action of your controller.
EntityTag.where(["user_id = ? and entity_id = ? and post_id = ?",
params[:user_id], params[:entity_id], params[:post_id]]).all
will return an Array of any existing record that have those same values. If Array.count == 0, then you can continue to save the newly created object as normal. Otherwise you can either return the existing record or throw an error; it's up to you.