Active Admin NoMethodError Error - ruby-on-rails

Im setting up active admin on my rails app. I ran the generator to create the user resource but when i click on the users link on the admin dashboard i get:
NoMethodError in Admin/users#index
Showing /Users/nelsonkeating/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/gems/1.9.1/gems/activeadmin-0.4.4/app/views/active_admin/resource/index.html.arb where line #1 raised:
undefined method `city_id_contains' for #<MetaSearch::Searches::User:0x007fde92d69840>
Extracted source (around line #1):
1: render renderer_for(:index)
I have no clue what is generating this or where the error is coming from.. Any ideas? Thanks! (please let me know if you need to see any other files)
Models:
user.rb
class User < ActiveRecord::Base
rolify
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :province_id, :city_id
belongs_to :province
belongs_to :city
province.rb
class Province < ActiveRecord::Base
has_many :cities
has_many :users
end
city.rb
class City < ActiveRecord::Base
belongs_to :province
has_many :users
end
schema.rb
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "name"
t.date "date_of_birth"
t.string "address"
t.string "gender"
t.integer "zipcode"
t.string "city"
t.string "status"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "province_id"
t.integer "city_id"
end
create_table "provinces", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "cities", :force => true do |t|
t.string "name"
t.integer "province_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end

This question helped me solve my problem. I had to read the comments to figure out how to solve it so I am providing the answer here:
If you have a model that contains a belongs_to relationship, Active Admin will not like it if you have a column name that matches your belongs to foreign key id column name.
For instance in this case your foreign key is 'city_id' but you also have a column named 'city'. Active Admin doesn't like this. And likewise it really doesn't make sense to have that column to begin with. Since you will access the city through the relationship.
To fix this you should create a migration that removes the city column.
class RemoveCityFromUser < ActiveRecord::Migration
def up
remove_column :users, :city
end
end

Related

Users, form and tasks association rails

I have an app allowing a user to fill a form (named "checklist") and then have a list of tasks he will have to do. The tasks (named "advices") are related to the answers that the user gave in the form.
For example, if a question is "have you cooked dinner ?" and the user answers "no", then an advice "go cook dinner" will be displayed.
Once a advice is done, the user can mark it as completed. Advices are the same for all users. They already are created in the app by admin.
So users have a checklist, checklist belongs to a user.
The problem I encounter is : when a user marks an advice as completed, it is marked as completed for all users. That should not be.
I am not really sure how to fix this. Associations "Has-many", and "Belongs_to" between advices and users should not work since the user does not create the advices ?
I am new to rails so I would be happy if someone could help.
Note that I use Devise to manage users.
Schema :
ActiveRecord::Schema.define(version: 20160407143608) do
create_table "advices", force: :cascade do |t|
t.string "name"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id"
t.boolean "status"
t.string "linkname1"
t.text "link1"
t.text "link2"
t.string "linkname2"
t.text "link3"
t.string "linkname3"
t.integer "ref"
t.boolean "completed"
end
create_table "categories", force: :cascade do |t|
t.string "name", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "checklists", force: :cascade do |t|
t.boolean "facebook"
t.boolean "twitter"
t.boolean "linkedin"
t.boolean "viadeo"
t.boolean "instagram"
t.boolean "community"
t.boolean "cms"
t.boolean "seo"
t.boolean "crowdfunding"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
add_index "checklists", ["user_id"], name: "index_checklists_on_user_id"
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Models :
class Advice < ActiveRecord::Base
belongs_to :category
end
class Checklist < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :checklists
end
View :
<%= advice.name %> | <%= link_to "Completed", complete_advices_path(advice), method: :put %>
controller :
def complete
#advice.completed = true
#advice.save
redirect_to root_path
end
You need a join model.
$ rails g model UserAdvice user:references advice:references
class UserAdvice
belongs_to :user
belongs_to :advice
end
in user.rb
has_many :user_advices
has_many :advices, through: :user_advices
in advice.rb
has_many :user_advices
has_many :users, through: :user_advices
Create a record in the join model when something gets checked off and then query that table to make sure the task is done for an individual user.
So, when a user checks off a task and submits, instead of using the completed boolean, you'd actually create a record that has the advice_id and the user_id. Then if that record exist for that advice, it should be checked off for that user. Does that make sense?
If you were hiding the completed tasks from users who had completed them, for instance, you could say something like
<% if UserAdvice.where(user_id: current_user.id, advice_id: advice.id).count > 0 %>
This will work, and is fine at first, but doing it this way could slow down your app, though. If there are a lot of advices, what you'd probably want to do is run the query once and get all the user_advice records and pluck the ids. Then check against that array of ids against the individual record.
In your controller
# this will return an array of advice_ids
#user_advices = UserAdvice.where(user_id: current_user).pluck(:advice_id)
Then, as you iterate through advices in your view:
<% unless #user_advices.include?(advice.id) %>
show the advice
<% end %>
EDIT:
To create the record inside that complete action:
def complete
UserAdvice.create(user_id: current_user.id, advice_id: #advice.id)
redirect_to root_path
end

Rails uniqueness validation based on relation

I have two models...
create_table "registrations", :force => true do |t|
t.integer "orientation_id"
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "student_id"
...
end
create_table "orientations", :force => true do |t|
t.date "class_date"
t.text "class_time"
t.integer "seats"
t.boolean "active", :default => true
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
I want to create a validation in my registration model that says the student_id must be unique in each Orientation.
If i understood your question correctly,you want the scope option of the validates_uniqueness_of.If so,this should work
In your Registration model,
Class Registration < ActiveRecord::Base
......
validates_uniqueness_of :student_id, scope: :orientation_id
end
And also,you should be generating a migration to add this
add_index :registration, [ :student_id, :orientation_id ], :unique => true
More Info here

Show most rated objects. Letsrate, Rails

I have some problem. I want to show the best hotels on page 5, but I do not know how to do it. I maintenance used gem letsrate.
schema.rb
create_table "hotels", force: true do |t|
t.string "title"
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
t.string "author"
t.boolean "breakfast"
t.decimal "price"
t.string "avatar"
t.integer "address_id"
end
create_table "rates", force: true do |t|
t.integer "rater_id"
t.integer "rateable_id"
t.string "rateable_type"
t.float "stars", null: false
t.string "dimension"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "rates", ["rateable_id", "rateable_type"], name: "index_rates_on_rateable_id_and_rateable_type"
add_index "rates", ["rater_id"], name: "index_rates_on_rater_id"
create_table "rating_caches", force: true do |t|
t.integer "cacheable_id"
t.string "cacheable_type"
t.float "avg", null: false
t.integer "qty", null: false
t.string "dimension"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "rating_caches", ["cacheable_id", "cacheable_type"], name: "index_rating_caches_on_cacheable_id_and_cacheable_type"
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
rate.rb
class Rate < ActiveRecord::Base
belongs_to :rater, :class_name => "User"
belongs_to :rateable, :polymorphic => true
#attr_accessible :rate, :dimension
end
hotel.rb
class Hotel < ActiveRecord::Base
belongs_to :user
belongs_to :address
letsrate_rateable 'Rating'
mount_uploader :avatar, AvatarUploader
accepts_nested_attributes_for :address
end
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
letsrate_rater
has_many :hotels
end
Please
I know how to do this using sql query, but I just started learning RoR and I'm sure there are more elegant way that someone can suggest?
First you have to change the dimension name to be downcased, otherwise it wouldn't map to your table names and the uppecase relation names this gem generated wouldn't follow rails conventions.
#Hotel
letsrate_rateable 'rating'
To show top n hotels by rating, run
Hotel.includes(:rating_average).order("rating_caches.avg DESC").limit(n)
You have to also add an index to the avg field in rating_caches
Have also a look on letsrate_rateable method. It just defines some associations based on the dimnesion names

Rails Notifications of New Posts

I am developing a rails app where users can post, must like facebook. I want to implement a notification systems that alerts users to new posts. However, I am having trouble on how to tell if a user has viewed posts or not. I am literally clueless.
I am using devise gem which gives me access to certain user stats (if this helps):
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "failed_attempts", :default => 0
t.string "unlock_token"
t.datetime "locked_at"
t.string "authentication_token"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "username", :default => "", :null => false
t.integer "admin", :default => 0
end
And my post model:
create_table "posts", :force => true do |t|
t.integer "user_id"
t.text "content"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
How can I implement a system that knows if a user has seen a post or not?
simple aproach would be like that:
create a model called Seen
rails g model Seen post:references user:references
models/seen.rb
belongs_to :user
belongs_to :post
models/user.rb
has_many :seens
has_many :seen_posts, through: :seens, source: :post
models/post.rb
has_many :seens
has_many :seen_users, through: :seens, source: :user
and you can create a method something like that
models/post.rb
def seen_by?(user)
seen_user_ids.include?(user.id)
end
controllers/posts_controller.rb
def show
#post = Post.find(params[:id])
current_user.seen_posts << #post unless #post.seen_by?(current_user)
end

How to get this one-to-one assoication working?

I've created a one-to-one association between my Admin and Report models and it isn't working just yet. I'm using Devise to log in via an Admin model so in the controller I'm using the current_admin helper. Silly question, but what migration do I need to run to get this working?
Error
ActiveRecord::StatementInvalid (PGError: ERROR: column reports.admin_id does not exist
2011-10-14T09:16:57+00:00 app[web.1]: LINE 1: SELECT "reports".* FROM "reports" WHERE ("reports".admin_id = ...
Report model
belongs_to :admin, :foreign_key => "admin_id"
Admin model
has_one :report, :foreign_key => "admin_id"
Controller
#report = current_admin.report
Schema
create_table "reports", :force => true do |t|
t.string "name"
t.string "description"
t.datetime "created_at"
t.datetime "updated_at"
t.string "user_id"
end
create_table "admins", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
You need admin_id in reports. You can remove the foreign_key stuff in your models. That's done automatically. Create a migration, add
add_column :reports, :admin_id, :integer
Run rake db:migrate and you're done.

Resources