audited, Look up audits belonging to a user - ruby-on-rails

I am using audited to track changes for a model called Page. I would like to be able to find all audits associated with a certain user (via user_id in the audits table).
How can I do that? So far, the only way I have found to access the Audit model is like this:
#audits = Audited::Adapters::ActiveRecord::Audit.all
Which just doesn't seem like it's the right way to do things.
Trying #audits = Audit.all gives an Uninitialized constant error.
Is there a more graceful way of interacting with models provided by gems?

Maybe something like
include Audited::Adapters::ActiveRecord::Audit
and then you can do
#audits = Audit.all
?
I think that should work... Or better yet:
include Audited

You can access all Audit records with
Audited::Audit.all
I got the result when I typed the
Audited.audit_class
DEPRECATION WARNING: audit_class is deprecated and will be removed
from Rails 5.0 (Audited.audit_class is now always Audited::Audit. This
method will be removed.).

I know this isn't an efficient way to do so, but this is how I do it.
In a Rails console I retrieve a record which I know is audited.
#page = Page.first
I then retrieve that record's first audit.
#audit = #page.audits.first
You can then call #class on #audit
#audit.class
Result:
Audited::Adapters::ActiveRecord::Audit(id: integer, created_at:
datetime, updated_at: datetime, auditable_id: integer, auditable_type:
string, user_id: integer, user_type: string, username: string, action:
string, audited_changes: text, version: integer, comment: string,
full_model: text, remote_address: string, associated_id: integer,
associated_type: string, request_uuid: string)
Audited::Adapters::ActiveRecord::Audit is the class name, which you can then use in your search.
audits = Audited::Adapters::ActiveRecord::Audit.where(:user_id => 8675309)

Related

How do I define products with only specific property tags (Spree, Rails)

I've got a custom Spree app. I need to query Spree::Products that have the associated Spree::Property
I have a 'property' with the name "Rating" on only certain products, but I can't query those products correctly. What I have now is:
Spree::Product.joins(:properties).where(:property_name.downcase == "rating")
but that just pulls all the products that have any :properties associated with them at all.
Spree::Property -
Spree::Property(id: integer, name: string, presentation: string, created_at: datetime, updated_at: datetime)
Just tested on Spree 3.1. You can do that from Product or Property model.
Spree::Product.joins(:properties).where(spree_properties: {name: "rating"})
or
Spree::Property.where(name: "rating").first.products
*You have to modify the code to use downcase string.

Inherited class cannot find table

I have three models using inheritance, and a table named 'telecom_circuits'.
class Telecom::Circuits::BaseCircuit < ActiveRecord::Base
end
class Telecom::Circuit < ::Telecom::Circuits::BaseCircuit
...
end
class Telecom::Circuits::AttVoiceCircuit < ::Telecom::Circuit
self.table_name = 'telecom_circuits'
end
When I do a create on the inherited class, it cannot find the table.
[1] pry(main)> Telecom::Circuits::AttVoiceCircuit
=> Telecom::Circuits::AttVoiceCircuit(id: integer, user_id: integer, division_id: integer, raw_site_id: integer, install_date: date, saville_account_number: string, account_number: string, meg8_account_number: string, main_circuit_id: string, d_channel: string, d_channel_type: string, ds3_access_circuit_id: string, lec_circuit_id: string, cli: string, lso: string, apn_ct1: string, dchan_cost: decimal, monthly_recurring_cost: decimal, created_at: datetime, updated_at: datetime, circuit_provision_type: string, trunk_group: string, apn_ct2: string, slot: string, disconnect_date: datetime, disconnect_requester_id: integer, disconnect_processor_id: integer, telecom_site_id: integer)
[2] pry(main)> Telecom::Circuits::AttVoiceCircuit.create
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'itrc_dev.telecom_base_circuits' doesn't exist: SHOW FULL FIELDS FROM `telecom_base_circuits`
from /Users/mpierc200/.rvm/gems/ruby-1.9.3-p327#itrc/gems/activerecord-3.2.14/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `query'
[3] pry(main)> Telecom::Circuits::AttVoiceCircuit.table_name
=> "telecom_circuits"
How do I get the inherited class to find the table? Keep in mind, I will need other inherited classes with different tables.
This looks like a bug in Rails 3.2 that is fixed in Rails 4.0.0.
ETA: Actually, you might need to add abstract class to fix your immediate problem but then hit this bug ;)
Also see this related Documentation commit.
ETA again: A closed rails issue sounds related as well; having non-abstract-classes and table-per-class inheritance looks unsupported.
You have a lot of concepts at play here. Ruby Inheritance, Rails STI, and Namespacing.
First, it seems like you're confusing Ruby's Object Oriented Inheritance with Rails Single Table inheritance (STI) because they both confusingly use inheritance. However with STI the key takeaway is the words single table. Rails STI makes the assumption that all objects will be saved into one table and that the model will add their class name into the extra db column called type. This column needs to exist for STI to work. It also allows you to fetch them via their class_name
Telecom::Circuits::Base.all
or
Telecom::Circuits::AttVoice.all
Your code as I understand it should be
# in app/telecom/circuit.rb
class Telecom::Circuit < ActiveRecord::Base
...
end
# in app/telecom/circuits/base.rb
class Telecom::Circuits::Base < Telecom::Circuit
...
end
# in app/telecom/circuits/att_voice.rb
class Telecom::Circuits::AttVoice < Telecom::Circuit
...
end
I took the liberty of making base and att_voice a subclass of circuits as I assumed that they are both independent types of circuits. If base has functionality that the other sub classes share and add on too then this class is redundant and the code would go into the Telecom::Circuit class.
If this isn't what you want, you're outside of the ActiveRecord model used in Rails. You may need to give each its own fully fledged table. Or perhaps you can utilize DataMapper or the new ROM to achieve your means.
Hope this helps!
You shouldnt inherit more than 1 level with rails, it becomes complicated and doesn't work very well. I had a similar structure and went back to only a single inheritance.
Im not sure if this works, but did you try it also with:
class BaseCircuit < ActiveRecord::Base
end
class Circuit < BaseCircuit
...
end
class AttVoiceCircuit < Circuit
...
end
so without namespaces? Table name should be "base_circuits"
Edit:
In the answers someone suggested the problem is with more than one level of inheritance or namespaces. I tried the following:
class BaseSo < ActiveRecord::Base
end
class AttVoice < BaseSo
self.table_name = 'telecom_circuits'
end
class ComcastVoice < BaseSo
self.table_name = 'telecom_pri_circuits'
end
with these results:
[1]pry(main)> AttVoice
=> AttVoice(id: integer, user_id: integer, division_id: integer, raw_site_id: integer, install_date: date, saville_account_number: string, account_number: string, meg8_account_number: string, main_circuit_id: string, d_channel: string, d_channel_type: string, ds3_access_circuit_id: string, lec_circuit_id: string, cli: string, lso: string, apn_ct1: string, dchan_cost: decimal, monthly_recurring_cost: decimal, created_at: datetime, updated_at: datetime, circuit_provision_type: string, trunk_group: string, apn_ct2: string, slot: string, disconnect_date: datetime, disconnect_requester_id: integer, disconnect_processor_id: integer, telecom_site_id: integer)
[2] pry(main)> AttVoice.table_name
=> "telecom_circuits"
[3] pry(main)> ComcastVoice
=> ComcastVoice(id: integer, created_at: datetime, updated_at: datetime, order_submitter: string, division_id: integer, lead_id: integer, pin: integer, raw_site_id: integer, site_poc: string, install_date: date, csg_billing_number: string, gl_code: string, pri_count: integer, pri_type: string, port_native: boolean, did_range: string, did_count: integer, comments: string, telecom_site_id: integer)
[4] pry(main)> ComcastVoice.table_name
=> "telecom_pri_circuits"
[5] pry(main)> AttVoice.count
(41.8ms) SELECT COUNT(*) FROM `telecom_circuits`
=> 2247
[6] pry(main)> AttVoice.create
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'itrc_dev.base_sos' doesn't exist: SHOW FULL FIELDS FROM `base_sos`
from /Users/mpierc200/.rvm/gems/ruby-1.9.3-p327#itrc/gems/activerecord-3.2.14/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `query'
[7] pry(main)> ComcastVoice.count
(0.4ms) SELECT COUNT(*) FROM `telecom_pri_circuits`
=> 155
[8] pry(main)> ComcastVoice.create
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'itrc_dev.base_sos' doesn't exist: SHOW FULL FIELDS FROM `base_sos`
from /Users/mpierc200/.rvm/gems/ruby-1.9.3-p327#itrc/gems/activerecord-3.2.14/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `query'
Would modules and mixins handle this for you?
See here.

Rails split string value as group of object

I currently receive from a form a string who looks like that :
one tag,another tag,yet another
Inside my Rails app I implemented a polymorphic association :taggable in order to manage tag (taxonomy) on my system. What I want now is to save those value in the database with of course, the less code as possible. My tables structure looks like that :
// Assocition table
TermRelationship(id: integer, taggable_id: integer, taggable_type: string, created_at: datetime, updated_at: datetime)
// Term table (tag)
Term(id: integer, name: string, created_at: datetime, updated_at: datetime, type: string)
// Blog table
Blog(id: integer, title: string, body: text, created_at: datetime, updated_at: datetime)
So far what I did is to split those value as an array :
tags = params[:blog][:tag].split(/,/)
Now the only I can think of is to have a loop in order to add one by one each value. But Im sure there is another "Rails/Ruby"-like to do it.
Thank you for your help
Do not reinvent the wheel. Take a look at https://github.com/mbleigh/acts-as-taggable-on

About Query methods Conditions in Rails 3

Hash way works just fine:
drummers = Drummer.where(:gender => true)
=> [#<Drummer id: 1, first_name: "Bernard", middle_name: nil, second_name: "Purdie", nick_name: "Pretty Purdie", gender: true, created_at: "2010-12-05 02:47:56", updated_at: "2010-12-05 02:50:42">]
But the same thing in String way:
drummers = Drummer.where("gender = true")
I got below error:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: TRUE: SELECT "drummers".* FROM "drummers" WHERE (gender = TRUE)
anybody could tell mewhy?
This is a sqlite error, not rails. When you say gender = true, it's looking for a column that is named true. Sqlite does not have booleans, so the correct way to do this is Drummer.where("gender = 1").
You should avoid using strings where possible in your Arel queries.
If you're joining a table that also contains a field named 'gender' then this will break, because it's ambiguous. Using where(:gender => true) will automatically be namespaced for you, so that won't happen.
As your example shows, using strings also can create portability problems, if you're using a feature that your backend doesn't support.
I've been using a plugin called MetaWhere to augment ARel's syntax, making strings less necessary.

Ruby On Rails ActiveRecord model not showing "blacklist" field

So I'm trying to rough out a design in Ruby, and so I ran
ruby script/generate scaffold item name:string description:text model:string manufacturers_name:string category:string weight:decimal upc:string ebay_cat_id:string blacklist:bool in_discovery:bool archived:bool
The only problem is that none of the bool fields are on the model. If I use ruby script/consol and run
item = Item.new
I get
#<Item id: nil, name: nil, description: nil, model: nil, manufacturers_name: nil, category: nil, weight: nil, upc: nil, ebay_cat_id: nil, created_at: nil, updated_at: nil>
Is there a limit to how many fields it will show on the object? I know the fields were created in the database... double checked that.
Come to think of it the date timestamps aren't on the object either. Any hints for me? Do I have to manually write accessors for these or what?
Have you tried:
blacklist:boolean
It looks like you must declare the full name, the docs say:
Instantiates a new column for the table. The type parameter is normally one of the migrations native types, which is one of the following: :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean.
Just like you cannot use int, you must declare integer
To answer the second part of your question, Yes! there is a limit to the number of columns you may have, 4096.
It's likley that once the interpreter hit "bool" it nixed the latter column names and types, that is why you're probably missing your timestamps and what not.

Resources