Rails ActionView::Template::Error undefined method `count' Resolver - ruby-on-rails

Note: I am using ruby 2.5.1 and rails 4.2.10
I am getting an error in my rails project and I believe it is because one of my classes is called Resolver. Here are the relevant files:
Migration
class CreateResolvers < ActiveRecord::Migration
def change
create_table :resolvers do |t|
t.belongs_to :user, index: true
t.string :name
end
end
end
Class
class Resolver < ActiveRecord::Base
belongs_to :user
end
Controller
class ResolversController < ApplicationController
def create
ent = Entity.new(entity_params)
ent.save!
redirect_to '/getting_started/resolvers'
end
def update
resToUpdate = Resolver.find(params['id'])
resToUpdate.update(resolver_params)
redirect_to '/getting_started/resolvers'
end
private
def resolver_params
params.require('resolver').permit(
:name
)
end
end
So here is my error: When I go into the rails console and do Resolver.count, it works fine, but in my actual html page, I have the line:
<% if (Resolver.count > 0) %>
and I am getting an error of:
undefined method 'count' for ActionView::Resolver:Class
Now, obviously that ActionView::Resolver:Class is not correct. I tried changing them to ::Resolver and ActiveRecord::Base::Resolver and neither worked. How can I use a class named Resolver without rails assuming it is this ActionView::Resolver

Having queries in the view is an antipattern.
The correct way of doing it anyway is to do it in the controller and pass the variable to the view.
#resolvers_count = Resolver.count and in the view check on if #resolvers_count > 0
a better way is
#resolvers_exist = Resolver.exists? and then if #resolvers_exist

Isn't it better to define a instance variable at the controller like
#resolver_count = Resolver.count so you can reach the count by calling #resolver_count on your view?

Related

Rails: Duplicate records created at the same time

There is something weird happening with my Rails app. A controller action is called and saves a record to a table each time a user visits a unique url I created before.
Unfortunately, sometimes two identical records are created instead of only one. I added a "validates_uniqueness_of" but it's not working.
My controller code:
class ShorturlController < ApplicationController
def show
#shorturl = ShortUrl.find_by_token(params[:id])
#card = Card.find(#shorturl.card_id)
#subscriber = BotUser.find_by_sender_id(params['u'])
#letter_campaign = Letter.find(#card.letter_id).campaign_name.downcase
if AnalyticClic.where(card_id: #card.id, short_url_id: #shorturl.id, bot_user_id: #subscriber.id).length != 0
#object = AnalyticClic.where(card_id: #card.id, short_url_id: #shorturl.id, bot_user_id: #subscriber.id)
#ccount = #object[0].clicks_count
#object.update(updated_at: Time.now, clicks_count: #ccount += 1)
else
AnalyticClic.create(card_id: #card.id, short_url_id: #shorturl.id, bot_user_id: #subscriber.id, clicks_count: "1".to_i)
end
#final_url = #card.cta_button_url
redirect_to #final_url, :status => 301
end
end
And the model:
class AnalyticClic < ApplicationRecord
validates_uniqueness_of :bot_user_id, scope: :card_id
end
Any idea why sometimes I have duplicated records? The if should prevent that as well as the validates_uniqueness_of.
First off, I believe your validation may need to look something like (although, TBH, your syntax may be fine):
class AnalyticClic < ApplicationRecord
validates :bot_user_id, uniqueness: { scope: :card_id }
end
Then, I think you should clean up your controller a bit. Something like:
class ShorturlController < ApplicationController
def show
#shorturl = ShortUrl.find_by_token(params[:id])
#card = Card.find(#shorturl.card_id)
#subscriber = BotUser.find_by_sender_id(params['u'])
#letter_campaign = Letter.find(#card.letter_id).campaign_name.downcase
analytic_clic.increment!(:click_count, by = 1)
#final_url = #card.cta_button_url
redirect_to #final_url, :status => 301
end
private
def analytic_clic
#analytic_clic ||= AnalyticClic.find_or_create_by(
card_id: #card.id,
short_url_id: #shorturl.id,
bot_user_id: #subscriber.id
)
end
end
A few IMPORTANT things to note:
You'll want to create an index that enforces uniqueness at the database level (as max pleaner says). I believe that'll look something like:
class AddIndexToAnalyticClic < ActiveRecord::Migration
def change
add_index :analytic_clics [:bot_user_id, :card_id], unique: true, name: :index_bot_user_card_id
end
end
You'll want to create a migration that sets :click_count to a default value of 0 on create (otherwise, you'll have a nil problem, I suspect).
And, you'll want to think about concurrency with increment! (see the docs)
You need to create unique index in your database table. There might be 2 processes getting to create condition together. The only way to stop these duplicate records is by having uniqueness constraint at DB level.

Using Rails helpers in model

In my model I have a method that marks a record as pending by changing its status to 2. After which it calls another method in another controller to create a notification containing details of the record that was changed.
e.g.
class Page < ActiveRecord::Base
def pend_page
self.update(status: 2)
Notification.create_notification("#{link_to self.title, pages_path(:status => 2)} marked as pending", #current_user)
end
end
However it seems Rails doesn't pass helpers for link_to and the routes to the models... as I get the error: undefined method 'pages_path' for #<Page:0x007fd15c996c88>.
How can I make it so that the link_to and pages_path work?
I'm using Rails 4.2.5.1
edit: here is what create_notification looks like:
class Notification < ActiveRecord::Base
belongs_to :user
def self.create_notification(content, user)
notification = Notification.new
notification.content = content
notification.user_id = user.id
notification.status = 0
notification.save
end
end
This should go in either a service object or in a PORO (plain old ruby object). A model's concerns should begin and end with database related functionality, anything else is in the wrong place.

How to test module using concerns and associations, via dummy ActiveRecord model in specs

What is the best way to test a module that uses associations, with a dummy active record class?
module Outputable
extend ActiveSupport::Concern
included do
has_one :output, as: outputable
end
delegate :print, to: :output
end
To use this module in a class, you'd make a new ActiveRecord model:
class Program < ActiveRecord::Base
include Outputable
def initialize(output)
self.output = output
end
end
prog = Program.create(Output.create)
prog.print("hello world") # delegates to Output.print
I want to be able to use several types of classes, for example Program, Log, etc. But I have not defined these ActiveRecord models yet, I'd like to test with a dummy class in specs (similar to this SO question). I've tried the Temping gem, but maybe it is outdated, using Rails 4, Ruby 2.1.2 I get:
when trying to do DummyProgram.create(output) from:
Temping.create :dummy_program do
include Outputable
def initialize(output)
self.output = output
end
end
describe Outputable
let(:output) { Output.create }
let(:prog) { DummyProgram.create(output) }
it "exposes Output methods" do
expect(output).to receive(:print)
prog.print("hello world!")
end
end
I get a strange undefined method '[]' for nil:NilClass method for the DummyProgram.create(output). It works how ever if I do DummyProgram.new(output) but I need it to be saved to the temporary db.
Has anyone encountered a way around this, or an alternative to temping gem?
Update: For now, I'm going with manually creating and dropping a table:
describe Outputable do
let(:output) { Output.create }
let(:prog) { DummyProgram.create(output: output) }
class DummyProgram < ActiveRecord::Base
include Workflows::Outputable
end
before :all do
m = ActiveRecord::Migration.new
m.verbose = false
m.create_table :dummy_program do |t|
t.integer :workflow_id
t.string :workflow_type
t.timestamps
end
end
after :all do
m = ActiveRecord::Migration.new
m.verbose = false
m.drop_table :dummy_program
end
...
end

Rails 4 - Uninitialized constant Mongo Model

I am attempting to setup MongoHQ using Heroku and rails 4. I have everything setup correctly to my knowledge, but I'm now getting this error:
uninitialized constant Job::TempEmailContactStoreCsv
This is the Job model where error is happening:
class Job < ActiveRecord::Base
belongs_to :user
def store_email_contact_csv(file)
contact_array = csv_to_array(file)
TempEmailContactStoreCsv.create(email_contact_array: contact_array, job_id: id)
end
end
And my mongo model:
class TempEmailContactStoreCsv
include Mongoid::Document
field :email_contact_array, type: Array
field :job_id
def self.store(job_id, email_contact_array)
r = TempEmailContactStoreCsv.find_by(job_id: job_id)
if (r.nil?)
TempEmailContactStoreCsv.create!(job_id: job_id, email_contact_array: email_contact_array)
end
end
def self.exists?(job_id)
r = TempEmailContactStoreCsv.find_by(job_id: job_id)
return r.nil? == false
end
def self.retrieve(job_id)
return TempEmailContactStoreCsv.find_by(job_id: job_id)
end
def self.delete(job_id)
r = TempEmailContactStoreCsv.find_by(job_id: job_id)
r.destroy unless r.nil?
end
end
So it seems that my mongo model is not being initialized, and the namespacing seems weird to me also.
Any thoughts as to what is causing this error and how to fix it?
For rails to load a class automatically, the file must be within rails load path (which includes app/models so you are fine there) and the file name should be the camelcased version of the class name.
In your case the file name should be temp_email_contact_store_csv.rb not temp_email_store_csv.rb

How do you define a class method?

I have a model OutcomeData with controller OutcomeDatas.
In OutcomeData, I have a method as_cleaned_hash that right now, doesn't do a damn thing. Let's just pretend it returns 'hello'
class OutcomeData < ActiveRecord::Base
attr_accessible :key, :outcome_uid, :task_id, :value
belongs_to :task
belongs_to :outcome
def as_cleaned_hash
'hello i am alive'
end
This is the method that as_cleaned_hash is supposed to follow, if it matters:
#outcome_data = OutcomeData.find_all_by_outcome_uid(params[:outcome_uid])
hash = Hash.new
#outcome_data.each do |p|
unless p[:value].blank? || p[:key] == 'raw'
hash[p[:key]] = p[:value]
end
end
This works fine -- right now I'm throwing it into my controller actions, but since it needs to be used throughout my app, I can't let this happen.
So, for whatever reason, I get an undefined method error.
I called OutcomeData.methods to see if the method was even there, and, nope. (see list here: http://pastebin.com/B3y1r2w7)
OutcomeData.respond_to?('as_cleaned_hash') returns false.
There's nothing fancy going on either, so I'm not quite sure what's happening.
Rails 3.2.12 with Ruby 2.0.0-p195
To define a class method, the syntax is
def self.foo
end
You have defined an instance method.

Resources