So I have a couple of models in my app and they are all registered with ActiveAdmin. They all work great except for one and I can't figure out why. I keep getting the same error:
NameError at /admin/reports
uninitialized constant Report::Users
The model that it is happening on is called Report
class Report < ActiveRecord::Base
belongs_to :users
belongs_to :cars
enum reason: [:accident,:totaled,:stolen]
validates :reason, presence:true
end
The controller looks like this:
Class ReportsController < ApplicationController
before_action :authenticate_user!
def create
#car=Car.find(params[:car_id])
#report=#car.reports.build(report_params)
#report.user_id=current_user.id
#report.car_id=#car.id
if #report.save
redirect_to car_path(car)
else
render 'new'
end
end
def destroy
#report=Report.find(params[:id])
#report.destroy
end
private
def report_params
params.require(:report).permit(:reason)
end
end
This is the migration used to create the model:
class CreateReports < ActiveRecord::Migration
def change
create_table :reports do |t|
t.references :user, index: true
t.references :car, index: true
t.integer :reason, default: 0
t.timestamps null: false
end
add_foreign_key :reports, :users
add_foreign_key :reports, :cars
end
end
Lastly here is the active_admin app/admin/report.rb:
ActiveAdmin.register Report do
# See permitted parameters documentation:
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
#
# permit_params :list, :of, :attributes, :on, :model
#
# or
#
# permit_params do
# permitted = [:permitted, :attributes]
# permitted << :other if resource.something?
# permitted
# end
end
I have been trying to figure it out for a couple of hours. Solutions that I saw on SO that don't work. I ran rails generate active_admin:resource Report to create it so it is singular. Why is it misbehaving?
NameError at /admin/reports uninitialized constant Report::Users
Association name for a belongs_to should be singular as per naming conventions.
class Report < ActiveRecord::Base
belongs_to :user #here
belongs_to :car #and here too
enum reason: [:accident,:totaled,:stolen]
validates :reason, presence:true
end
Related
I have a Company and a User model, both with a slug via friendly_id. Slugs are ensured to be unique across both models.
I'd like to have URLs:
http://www.example.com/any_company_name
http://www.example.com/any_user_name
e.g. both /apple and /tim
I'm not sure how to achieve this in Rails.
I have tried various permutations of:
routes.rb:
resources :users, path: ''
resources :companies, path: ''
get '*search', to: 'my_controller#redirect'
and
my_controller#redirect:
#company = Company.friendly.find(params[:search])
redirect_to #company if #company
#user = User.friendly.find(params[:search])
redirect_to #user if #user
However I can't get it to work. I can get /apple to redirect to /companies/apple and /tim to redirect to /users/tim (by removing the path: '' option) but this is not what I want to achieve.
Instead redirect with urls, you can redirect with controller#action by using url_for.
For example:
my_controller#redirect:
#company = Company.friendly.find(params[:search])
redirect_to url_for(action: 'show', controller: :companies , status: :success, company_id:#company.id)
#user = User.friendly.find(params[:search])
redirect_to url_for(action: 'show', controller: :users, status: :success,user_id:#user.id)
I had a similar problem and was able to solve it by creating a PublicSlug model with a slug attribute and a polymorphic association to a "Sluggable" class. I also used a Sluggable concern that I included in models I would like to query.
The PublicSlug model
class PublicSlug < ActiveRecord::Base
extend FriendlyId
friendly_id :sluggable_name, use: :slugged
belongs_to :sluggable, polymorphic: true
private
# Generate the slug based on the title of the Sluggable class
def sluggable_name
sluggable.name
end
end
The Sluggable concern
module Sluggable
extend ActiveSupport::Concern
included do
has_one :public_slug, dependent: :destroy, as: :sluggable
delegate :slug, to: :public_slug
end
end
Company and User models.
class User < ActiveRecord::Base
include Sluggable
end
class Company < ActiveRecord::Base
include Sluggable
end
I can now query both models using
Sluggable.friendly.find(slug).sluggable
The redirect could be handled in your controller as follows:
def redirect
#sluggable = Sluggable.friendly.find(params[:search]).sluggable
redirect_to #sluggable
end
Building off of #Essn's answer...
Still use a PublicSlug model:
# app/models/public_slug.rb
class PublicSlug < ActiveRecord::Base
extend FriendlyId
friendly_id :sluggable_name, use: :slugged
belongs_to :sluggable, polymorphic: true
validates :slug, presence: true, uniqueness: { case_sensitive: false }
private
# Generate the slug based on the title of the Sluggable class
def sluggable_name
sluggable.name
end
end
And a Sluggable concern:
# app/models/concerns/sluggable.rb
module Sluggable
extend ActiveSupport::Concern
included do
before_validation :create_public_slug
has_one :public_slug, dependent: :destroy, as: :sluggable
delegate :slug, to: :public_slug
private
def create_public_slug
self.public_slug = PublicSlug.new unless public_slug.present?
end
end
end
Include that concern in all models you want to lookup:
# app/models/user.rb
class User < ActiveRecord::Base
include Sluggable
...
end
Create a migration:
# db/migrate/...create_public_slugs.rb
class CreatePublicSlugs < ActiveRecord::Migration[5.0]
def change
create_table :public_slugs do |t|
t.references :sluggable, polymorphic: true
t.string :slug
end
end
end
Then you can lookup the model via:
# app/controllers/home_controller.rb
class HomeController < ApplicationController
# /:slug
def show
#sluggable = PublicSlug.friendly.find(params[:id]).sluggable
render #sluggable
end
end
I'm trying to create a simple # mentions model similar to twitters for my app. I've started building it, but I don't know how I would handle the actual creation of the mention. I need some way to scan let's say a status before it's created for any # symbols, then checking the text following against the database for any matching usernames. If there's a match then a mention gets created along with the status. Can someone point me in the right direction?
Here's what I have so far:
db/migrate/create_mentions.rb
class CreateMentions < ActiveRecord::Migration
def change
create_table :mentions do |t|
t.belongs_to :mentionable, polymorphic: true
t.timestamps
end
add_index :mentions, [:mentionable_id, :mentionable_type]
end
end
models/mention.rb
class Mention < ActiveRecord::Base
belongs_to :mentionable, polymorphic: true
end
models/status.rb
class Status < ActiveRecord::Base
attr_accessible :content
has_many :mentions, dependent: :destroy
end
models/member.rb
class Member < ActiveRecord::Base
has_many :mentions, as: :mentionable, dependent: :destroy
end
controllers/mentions_controller.rb
class MentionsController < ApplicationController
before_filter :authenticate_member!
before_filter :load_mentionable
before_filter :find_member
def new
#mention = #mentionable.mentions.new
end
def create
#mention = #mentionable.mentions.new(params[:mention])
respond_to do |format|
if #mention.save
format.html { redirect_to :back }
else
format.html { redirect_to :back }
end
end
end
private
def load_mentionable
klass = [Status].detect { |c| params["#{c.name.underscore}_id"] }
#mentionable = klass.find(params["#{klass.name.underscore}_id"])
end
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
end
config/routes.rb
resources :statuses do
resources :mentions
end
Thanks to this question: parse a post for #username I was able to get this working. My set up:
db/migrate/create_mentions.rb
class CreateMentions < ActiveRecord::Migration
def change
create_table :mentions do |t|
t.belongs_to :mentionable, polymorphic: true
t.belongs_to :mentioner, polymorphic: true
t.integer :status_id
t.integer :comment_id
t.timestamps
end
add_index :mentions, [:mentionable_id, :mentionable_type], :name => "ments_on_ables_id_and_type"
add_index :mentions, [:mentioner_id, :mentioner_type], :name => "ments_on_ers_id_and_type"
end
end
models/mention.rb
class Mention < ActiveRecord::Base
attr_accessible :mentioner_id, :mentioner_type, :mentionable_type, :mentionable_id, :status_id, :comment_id
belongs_to :mentioner, polymorphic: true
belongs_to :mentionable, polymorphic: true
end
models/member.rb
class Member < ActiveRecord::Base
has_many :mentions, as: :mentionable, dependent: :destroy
end
models/status.rb
class Status < ActiveRecord::Base
attr_accessor :mention
has_many :mentions, as: :mentioner, dependent: :destroy
after_save :save_mentions
USERNAME_REGEX = /#\w+/i
private
def save_mentions
return unless mention?
people_mentioned.each do |member|
Mention.create!(:status_id => self.id, :mentioner_id => self.id, :mentioner_type => 'Status', :mentionable_id => member.id, :mentionable_type => 'Member')
end
end
def mention?
self.content.match( USERNAME_REGEX )
end
def people_mentioned
members = []
self.content.clone.gsub!( USERNAME_REGEX ).each do |user_name|
member = Member.find_by_user_name(user_name[1..-1])
members << member if member
end
members.uniq
end
end
config/routes.rb
resources :statuses do
resources :mentions
end
helpers/mentions_helper.rb
module MentionsHelper
def statuses_with_mentions(status)
status.content_html.gsub(/#\w+/).each do |user_name|
member = Member.find_by_user_name(user_name[1..-1])
if member
link_to user_name, profile_path(member.user_name)
else
user_name
end
end
end
end
/config/routes.rb
Rails.application.routes.draw do
devise_for :users
root 'posts#hello'
resources :users
resources :posts
end
/app/controllers/posts_controller.rb
class PostsController < ApplicationController
before_filter :authenticate_user! , except: [:hello]
def hello
end
def new
end
def create
#post = Post.create(inner)
redirect_to post_path(#post.id)
end
def index
#posts = Post.all.order('id desc')
end
def show
#post = Post.find_by(id: params[:id])
end
private
def inner
params.require(:post).permit(:title, :desc)
end
end
When I click posts_path link, I get an error: uninitialized constant PostsController::Post app/controllers/posts_controller.rb, line 17
def index
#posts = Post.all.order('id desc')
end
Whats wrong?
UPD
class Post < ActiveRecord::Base
belongs_to :user
validates :desc, presence: true
validates :title, presence: true, length: { maximum: 45 }
end
UPD2
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.string :desc
t.timestamps
end
end
end
As per Rails convention model names should be singular. So, model Post would be located under folder app/models and named post.rb and NOT Posts.rb. You are getting the error because Rails would look for a file named post.rb by convention and if not found it throws the error.
I am currently following Ryan Bates tutorial on activity feed from scratch.
**I added a originator_id to the database so that I can save the ID of the Owner who originated the post. But for some reason I can't get it to work.
My Database from Scratch
class CreateActivities < ActiveRecord::Migration
def change
create_table :activities do |t|
t.belongs_to :user
t.string :action
t.belongs_to :trackable
t.string :trackable_type
###I want to save the id corresponding to User who created the object
t.belongs_to :originator
t.string :originator_type
t.timestamps
end
add_index :activities, :user_id
add_index :activities, :trackable_id
add_index :activities, :originator_id
end
end
Here is my Code
Models
class Activity < ActiveRecord::Base
belongs_to :user
belongs_to :trackable, polymorphic: true
belongs_to : originator, polymorphic: true
attr_accessible :action, :recipient, :trackable
###how can i set the originator_id value
after_create :set_originator
def set_originator
self.originator.update_attribute(:originator, ???)
end
end
Controllers
class ApplicationController < ActionController::Base
###sets the action and trackable values
###how can i the originator here. i keep getting an error saying undefined method
###why is it that rails recognizes trackable?
def track_activity(trackable, action = params[:action])
current_user.activities.create! action: action, trackable: trackable,
originator: originator
end
end
class LikesController < ApplicationController
def create
#like = Like.create(params[:like])
#dailypost = #like.dailypost
###Used to call track activity method above
track_activity #like
respond_to do |format|
format.js
format.html { redirect_to :back }
end
end
end
Don't know how solid this answer will be as i add more models to the activities, but this worked for my likes model.
If anyone can provide another solution that will work with multiple models i would really appreciate it. :)
class ApplicationController < ActionController::Base
def track_activity(trackable, action = params[:action])
current_user.activities.create! action: action, trackable: trackable,
originator: originator
end
def originator
#like.dailypost.user
end
end
Delayed::Job serializes your class, method & parameters into the handler field. We currently resort to hardcoding this serialized method into our code. This is gross.
How should we be constructing the handler so we can look up an existing queued up job?
This what I do:
1) Add two new columns to delayed_jobs table
db/migrations/20110906004963_add_owner_to_delayed_jobs.rb
class AddOwnerToDelayedJobs < ActiveRecord::Migration
def self.up
add_column :delayed_jobs, :owner_type, :string
add_column :delayed_jobs, :owner_id, :integer
add_index :delayed_jobs, [:owner_type, :owner_id]
end
def self.down
remove_column :delayed_jobs, :owner_type
remove_column :delayed_jobs, :owner_id
end
end
2) Add a polymorphic association to Delayed::Job model
config/initializers/delayed_job.rb
class Delayed::Job < ActiveRecord::Base
belongs_to :owner, :polymorphic => true
attr_accessible :owner, :owner_type, :owner_id
end
3) Monkey patch ActiveRecord::Base to contain a jobs association
config/initializers/active_record.rb
class ActiveRecord::Base
has_many :jobs, :class_name => "Delayed::Job", :as => :owner
def send_at(time, method, *args)
Delayed::Job.transaction do
job = Delayed::Job.enqueue(Delayed::PerformableMethod.new(self,
method.to_sym, args), 10, time)
job.owner = self
job.save
end
end
def self.jobs
# to address the STI scenario we use base_class.name.
# downside: you have to write extra code to filter STI class specific instance.
Delayed::Job.find_all_by_owner_type(self.base_class.name)
end
end
4) Triggering a jobs
class Order < ActiveRecord::Base
after_create :set_reminders
def set_reminders
send_at(2.days.from_now, :send_email_reminder)
end
def send_email_reminder
end
# setting owner for handle_asynchronously notation.
def foo
end
handle_asynchronously :foo, :owner => Proc.new { |o| o }
end
5) Inspecting jobs
Order.jobs # lists all the running jobs for Order class
order1.jobs # lists all the running jobs for Order object order1