what does default_scope -> { kept } in rails means? - ruby-on-rails

I am new to rails world. In one of the existing rails project I am working, I see a line in a model class as mentioned below. Can someone please tell me what does this signify. I tried searching documentation but couldn't find "kept" keyword anywhere.
default_scope -> { kept }

From what I get, this is a scope that might be provided by a gem that allows you to "discard" records (instead of deleting them). The default scope is set to only return results that are kept (i. e. not discarded). Of course the functionality could also be developed manually but then you'd find the code in your project (e. g. in the model or a concern).
A popular gem to achieve this would be https://github.com/jhawthorn/discard (not affiliated with it) which effectively uses kept. Maybe check your Gemfile what gems your project uses and search their docs for this.

Related

Updating a Rails model's attributes through mongoid using normal persistence methods

I have been chasing an issue down for a while now, and still cannot figure out what's happening. I am unable to edit documents made from my gem through normal persistence methods, like update or even just editing attributes and calling save.
For example, calling:
Scram::Policy.where(id: a.id).first.update!(priority: 12345)
Will not work at all (there are no errors, but the document has not updated). But the following will work fine:
Scram::Policy.collection.find( { "_id" => a.id } ).update_one( { "$set" => {"priority" => 12345}})
I am not sure what I'm doing wrong. Calling update and save on any other model works fine. The document in question is from my gem: https://github.com/skreem/scram/blob/master/lib/scram/app/models/policy.rb
I cannot edit its embedded documents either (targets). I have tried removing the store_in macro, and specifying exactly what class to use using inverse_of and class_name in a fake app to reimplement these classes: https://github.com/skreem/scram-implementation/blob/master/lib/scram/lib/scram/app/models/policy.rb
I've tried reimplementing the entire gem into a clean fake rails application: https://github.com/skreem/scram-implementation
Running these in rails console demonstrates how updating does not work:
https://gist.github.com/skreem/c70f9ddcc269e78015dd31c92917fafa
Is this an issue with mongoid concerning embedded documents, or is there some small intricacy I am missing in my code?
EDIT:
The issue continues if you run irb from the root of my gem (scram) and then run the following:
require "scram.rb"
Mongoid.load!('./spec/config/mongoid.yml', :test)
Scram::Policy.first.update!(priority: 32) #=> doesn't update the document at all
Scram::Policy.where(id: "58af256f366a3536f0d54a61").update(priority: 322) #=> works just fine
Oddly enough, the following doesn't work:
Scram::Policy.where(id: "58af256f366a3536f0d54a61").first.update(priority: 322)
It seems like first isn't retrieving what I want. Doing an equality comparison shows that the first document is equal to the first returned by the where query.
Well. As it turns out, you cannot call a field collection_name or else mongoid will ensure bad things happen to you. Just renaming the field solved all my issues. Here's the code within mongoid that was responsible for the collision: https://github.com/mongodb/mongoid/blob/master/lib/mongoid/persistence_context.rb#L82
Here's the commit within my gem that fixed my issue: https://github.com/skreem/scram/commit/25995e955c235b24ac86d389dca59996fc60d822
Edit:
Make sure to update your Mongoid version if you have dealt with this issue and did not get any warnings! After creating an issue on the mongoid issue tracker, PersistenceContext was added to a list of prohibited methods. Now, attempting to use collection_name or collection as a field will cause mongoid to spit out a couple of warnings.
Fix commit: https://github.com/mongodb/mongoid/commit/6831518193321d2cb1642512432a19ec91f4b56d

Class name conflict across modules

I'm running into an issue in a Rails 4 application related to class names and modules.
I have an Event class in my main application that inherits from ActiveRecord::Base. I also have a set of files in my /lib directory that have been grouped into a module I call LibModule. There's a class in that module that's also named Event. I noticed something interesting about referencing these classes. Here are some examples using the Rails console.
Example #1: When Event has never been referenced, the ActiveRecord version gets loaded:
> Event
=> Event(id: integer...)
Example #2: When LibModule::Event gets referenced first:
> LibModule::Event
=> LibModule::Event
> Event
=> LibModule::Event
As a result, when my server restarts (after updates, etc), I'll occasionally get the following error if a user engages in behavior that triggers server activity similar to Example #2:
superclass mismatch for class Event
I know there are a few ways to ensure that there's no conflict here. What's the best practice way of handling a situation like this?
I tried replicating the behavior from Example #2 with class names from gems and it seems like Rails completely segregates the classes in gems. Is there a way to do the same here? I think this would be my ideal situation.
Should I just change the name of LibModule::Event?
Should I ensure that the ActiveRecord class loads during initialization?
Some other Rails best practice I haven't thought of?
This has to do with the way qualified constants are resolved by the Rails autoloader. The documentation offers the following solution:
Naming conflicts of this kind are rare in practice, but if one occurs, require_dependency provides a solution by ensuring that the constant needed to trigger the heuristic is defined in the conflicting place.
The solution, in your case, is to add this just above the class definition for LibModule::Event:
require_dependency 'event'
This will inform the autoloader of the ::Event constant that references your ActiveRecord model, ensuring the appropriate constant naming for LibModule::Event.
Although there's nothing in Ruby that precludes you from having duplicated class names, the Rails auto-loader does get easily confused by them which can cause a lot of problems.
Typically I go out of my way to avoid duplication for this very reason. Sometimes they work, sometimes they don't, and the working/not-working aspect of the code can often depend on which entry point is taken, which things are loaded first, making it unpredictable.
You can try and circumvent this by force-loading your Event class using require_relative at the end of lib_module.rb.
to reference the main event class try ::Event. :: is a scope resolution operator, which specifies the global/main scope.

Problems Implementing ActiveModel Dirty Rails 3.2.8

I want to check when attributes on a model have changed. I have attempted to check values != the value on the form before doing a save but that code is really ugly and is not working well at times. Same with using update_column which does not do the validations in my model class. If I use update_attributes without doing something else I will not be able to check when a field has been updated from my understanding. From my web research on Stack Overflow and other sites it appears that using ActiveModel Dirty is the way to go.
I have looked at this: http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
My hope is to use this to check if boolean flags changed on a model after using update_attributes. I attempted to do the minimum implementation as described in the included link. I added the following to my ActiveRecord class:
include ActiveModel::Dirty
define_attribute_methods [:admin]
I tried adding the three attributes I wanted to keep track of. I started with just one attribute to see if I could get it working. I received the following error when I ran an rspec test. Once I removed the argument I had no errors.
Exception encountered: #<ArgumentError: wrong number of arguments (1 for 0)>
After I removed the argument I decided to include similar methods in my model using admin instead of name. Other Rspec tests broke on the save method. However I feel the problem is with how I am implementing ActiveModel Dirty.
I have read on other Stack Overflow posts where commenters stated that this was included in 3.2.8 so I upgraded from 3.2.6 to 3.2.8. I did not understand what that meant so after getting errors I decide just to leave the include ActiveModel::Dirty statement and try to use admin_changed? Of course it did not work.
I have not been able to find anything about how to initially set things up for this other than the link I included here. All the other research I have found assumes that the initial setup was correct and that updating to the current stable version of Rails would take care of their problems.
Any help would be appreciated on how to implement this. Doing the minimal implementation as stated in the link is not working. Maybe there is something else I am missing.
The problem appears to be that ActiveRecord redefines the define_attribute_methods method to accept 0 arguments (because ActiveRecord automatically creates attribute methods for every column in the database table): https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods.rb#L23
This overrides the define_attribute_methods method provided by ActiveModel: https://github.com/rails/rails/blob/master/activemodel/lib/active_model/attribute_methods.rb#L240
Solution:
I figured out a solution that worked for me...
Save this file as lib/active_record/nonpersisted_attribute_methods.rb: https://gist.github.com/4600209
Then you can do something like this:
require 'active_record/nonpersisted_attribute_methods'
class Foo < ActiveRecord::Base
include ActiveRecord::NonPersistedAttributeMethods
define_nonpersisted_attribute_methods [:bar]
end
foo = Foo.new
foo.bar = 3
foo.bar_changed? # => true
foo.bar_was # => nil
foo.bar_change # => [nil, 3]
foo.changes[:bar] # => [nil, 3]
However, it looks like we get a warning when we do it this way:
DEPRECATION WARNING: You're trying to create an attribute `bar'. Writing arbitrary attributes on a model is deprecated. Please just use `attr_writer` etc.
So I don't know if this approach will break or be harder in Rails 4...
See also:
Track dirty for not-persisted attribute in an ActiveRecord object in rails
https://github.com/adzap/validates_timeliness/issues/73
Try adding adding =, like this:
define_attribute_methods = [:admin]
That change worked for me. Not sure if it has something to do with this?

Reverse Engineering (Generating) Tables or Database Schema from Models and Views in Ruby on Rails

Update: The Question is Still Open, any reviews, comments are always welcome
I am having an existing rails project in which some important files and directories has been missed.
project rails version (2.3.8) i found it in environment.rb
currently what i am having is
app
controllers (already fully coded)
helpers (already fully coded)
models (already fully coded)
reports (already fully coded)
views (already fully coded)
config ---> default configurations (already fully coded)
lib ---> contains nothing
public --> contains images and scripts (already fully coded)
script ---> contains server,runner,plugin,dbconsole....
app directory fully contains working state of codes, app/model contains more than 100 .rb files , so i assume it will be more than 100 tables
the mainly missing things are db directory, .gem file, rake file, doc, test, vendor, database,schema.rb and migrations
Note:
i don't have the table schema and database for that project
i am in Need to generate tables or complete database from models and views and
i am looking for reverse engineering kind of stuff for generating db schema from models or views
I am newbie to rails and i am from java background , in java by using hibernate there is an pojo(model in rails) to database option available, i am looking for similar kind of stuffs for rails , and my main aim to run that project , so guys please help me.
To recreate the database schema, it will take quite a bit of time.
You can get a lot of information about the database in the app/models, app/controllers app/views directory.
You should know that ActiveRecord does not require you to explicitly list all the attributes of a model. This has important implications - you can only infer what attributes you still have to add to the database, based on whether an attribute is referred to! This means doing this will be a bit of an ART. And there are no CLEAR steps to complete this work. But below are some rules which you can use to HELP you.
This is a BIG project, below are guidelines, rules and tips to help you. But be aware that this could take a long time, and be frustrating at times to get this done.
What Tables you need:
Each table will normally have a matching ActiveRecord::Base model. So in the app/models directory, check each file, and if the class inherits from ActiveRecord::Base, it is an extra table.
The table name is by default a pluralized snake case version of the name of the class.
class UserGroup < ActiveRecord::Base # for this class
the name of the table is user_groups. Notice it is plural, and instead of camel case, it is lowercase, with underscores to separate the words.
All these tables will have an "id" integer column. By default, the tables also have a "created_at", and "updated_at" column of type datetime.
Associations and foreign keys:
You can infer what foreign keys exist by the associations in the Models. All associations are explicitly listed, so this is not too hard.
For example:
class UserGroup < ActiveRecord::Base # for this class
belongs_to :category
This means that the user_groups table has a column named "category_id", which is a foreign key for the categories table.
This means that the Category model likely has an inverse relationship (but no extra column):
class Category < ActiveRecord::Base
has_many :user_groups
The main other association is the has_many_and_belongs_to association. Eg.
class A < ActiveRecord::Base
has_and_belongs_to_many :bs
end
class B < ActiveRecord::Base
has_and_belongs_to_many :as
end
This means that there is a join table to add called "as_bs" (as and bs are sorted alphabetically), with the foreign keys "a_id" and "b_id".
All foreign keys are integers.
Attributes
Ok, so that's the table associations. Now for the normal attributes...
You should check the app/views/user_groups/ or other similar app/views directories.
Inside you will find the view templates. You should look at the _form.html.erb templates (assuming it is .erb templates, otherwise it could be .haml etc templates).
The _form.html.erb template, if it exists, will normally have many of the attributes listed as form fields.
In the form_for block, check if it says something like f.text_field :name, it means there is an attribute/(column in the table) called "name". You can infer what type the column should be by what type of field it is. Eg. in this case, it is a string, so maybe a VARCHAR(255) is appropriate (referred to as string in Rails).
You might also need to infer what type is appropriate based on the name of the attribute (eg. if it mentions something like :time, then it is probably either of type Time or DateTime).
This may give you all the other attributes in the table. But in some cases, you might miss the attributes. If you find a reference to other attributes in the controller, eg. app/controllers/user_groups_controller.rb, then you should add that as a column in your table. You can leave this until the end when you test it though, because when you test it, if an attribute is missing, then it will throw a NoMethodError for the object of the relevant model. Eg. if it says that #user_group variable, of class UserGroup, is missing a method named title, then it probably is missing a column named "title" of type string.
Recreate your migration/database
Ok, so now you know what the database tables and column names and types should be.
You should generate/recreate a migration for your database.
To do this, just use the command rails generate migration RecreateTables.
Then you should find a file in db/migrate/???_recreate_tables.rb.
Inside, start writing ruby code to create your tables. Reference for this can be found at http://guides.rubyonrails.org/migrations.html.
But essentially, you will have something like:
class RecreateTables < ActiveRecord::Migration
def up
create_table :user_groups do |t|
t.string :name # adds a string (VARCHAR) column called "name"
t.text :description # adds a textarea type column called "description
t.timestamps # adds both "created_at" and "updated_at" columns for you
end
end
def down
drop_table :products # this is the reverse commands to undo stuff in "up"
end
end
To recreate your Gemfile:
Start by adding a default Gemfile. This can be done by using rails new testapplication somewhere to create an empty rails application. Then copy the Gemfile to your actual application. It will get you started by including rails and other common gems.
It is VERY hard to work out exactly what gems are needed. The best you can do is try adding them one by one as you look through the code.
Again, here, MethodNotFound errors are your FRIEND. When you test the application, based on the gems you have added, it might detect some missing methods which might be supplied by gems. Some missing methods on models might indicate missing gems (or they might indicate missing fields/columns in the database). However, missing methods on Controller or ActiveRelation classes are VERY likely because of missing gems.
You will have to look through the code and try to infer what gems to add.
If it uses methods like can, can?, and has a file app/models/ability.rb, then you need gem 'cancan'. If it calls devise in a model, it needs gem 'devise'. Many common gems can be seen at http://ruby-toolbox.com.
After adding gems to your Gemfile, you should run bundle on your command line to install the new gems before testing again. When you test it again, you should restart your test server. Rerun bundle exec rails server to start a local test server on localhost:3000 or something like that.
You can simply copy the Rakefile from rails new testapp, and it will probably include everything you need.
Missing Tests
The missing test/ directory is not relevant to your actual application. It is not required to run the application. However, it does hold automatic scripts to test your application. You will have to re-write new tests if you want to automatically test your application. However for the purpose of getting your application back up, you can ignore it for now.
Missing vendor directory
Some extra code is not installed as a gem, but as a plugin. Anything installed as a plugin is lost if you don't have the vendor directory. As with gems, the best you can do is try to infer what might be missing, and re-download the missing plugin, either re-installing the plugin, or using a gem replacement.
Additional tips:
Try reading some of the comments which might name some of the gems used.
If a method or set of methods are missing, that you think are not database fields/columns, it might be due to a missing gem. The best thing to do is to search google for those method names. Eg. if it is missing "paginate", you can search "rails paginate gem", and see what likely gems you might need. This example will probably come up with "will_paginate", and "kaminari". Then you have to try and infer which of the gems are required. Maybe do a grep will_paginate app -r on the command line to see if it is using will paginate. The grep command searches for the string "will_paginate", in the directory called "app", -r makes it do this recursively for all files
Even though rails is a full stack web framework it would work with out some parts as well, if you wish to,
Ex: in your case
db - directory is there for keep the migrations to create you DB/tables, but if you are using a legacy DB or the database stuff is handled by DB administrators, you might not want it. (you can simply connect to the DB via database.yml file)
Gem file is helping you to keep all the gems (libraries) in one place as you do with Maven (in java)
test, again if you done write test cases (which is absolutely a bad idea), you done need this
vendor, is for 3rd party plugins and doc is for documentation, so same rule applies, if you done need them you can skip them
Hibernate in rails called "Activerecord", same concept, a model is bind with a database table (technically model represents a raw in the table)
So if you really want them add them but if not just leave them
BUT, I think having a proper Gem file and test cases is a must
welcome come to Rails
HTH
In the following, I assume you already know how to:
dump your database schema into an SQL file
start a Rails console (rails c)
generate a Rails migration
Here's what I think you should do.
Identify which of your classes correspond to physical tables (you mention some views in your question, which leads me to believe a subset of your models are bound to database views instead of actual tables). To do this you need to match the definitions of your models (classes which extend ActiveRecord::Base) to CREATE TABLE statements in your schema dump. For instance, class Person in your Ruby code matches to CREATE TABLE people in your DB schema dump.
Once you identified those models (class names), you start up a Rails console and you type those model names, one at a time, and press Enter. The console output for a model called Person would presumably look like this:
>> Person
=> Person(id: integer, first_name: string, last_name: string)
You then take what's inside the parentheses, strip the leading id: integer,, get rid of commas, get rid of those blanks after the colons, thus obtaining something like this:
first_name:string last_name:string
Having done this, the command to generate the migration would look like this:
rails g migration Person first_name:string last_name:string
You then start a new Rails project somewhere else, perform all of these migrations and inspect the contents of db/migrate. Your migrations are most likely 90% done, what you still need to do is replace some instances of t.integer with t.references, and other minor stuff that's completely domain-specific and impossible to capture in a generic answer.
HTH.

Rails 3.1. What's the easiest way to make chaining dropdown selects?

I was trying to make work this:
http://chainselects.hypermediasoft.com/
But got error:
Routing Error
uninitialized constant ChainSelectsHelper
So i have to make some break and ask community - is there any easy way to make chaining select boxes for my application forms?
UPDATE:
Maybe i should make editions in some config files? I can see thist ChainSelectsHelper in vendor/plugins/ChainSelects/lib/app/helpers/chain_selects_helper.rb. But why my application can't see this? Any assets pipeline configs needed?
And got this error in model:
undefined method `acts_as_chainable' for #<Class:0x007fe387542780>
From the looks of it, it seems that you did not add this in the controller:
include ChainSelectsHelper
Keep in mind that modifications have to be made to both model and controller, as stated here.

Resources