-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add foreign key option to Fields #807
Conversation
spec/lib/fields/deferred_spec.rb
Outdated
deferred.permitted_attribute(:foo) | ||
context "when not given a `foreign_key` option" do | ||
it "delegates to the backing class" do | ||
deferred = Administrate::Field::Deferred.new(Administrate::Field::String) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [81/80]
spec/lib/fields/belongs_to_spec.rb
Outdated
expect(field.permitted_attribute).to eq("customers_uuid") | ||
end | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra empty line detected at block body end.
spec/example_app/db/seeds.rb
Outdated
{code: 'DE', name: 'Germany'}, | ||
{code: 'CA', name: 'Canada'}, | ||
{code: 'BR', name: 'Brazil'}, | ||
]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indent the right bracket the same as the first position after the preceding left parenthesis.
spec/example_app/db/seeds.rb
Outdated
{code: 'RU', name: 'Russia'}, | ||
{code: 'DE', name: 'Germany'}, | ||
{code: 'CA', name: 'Canada'}, | ||
{code: 'BR', name: 'Brazil'}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space inside { missing.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
Space inside } missing.
spec/example_app/db/seeds.rb
Outdated
{code: 'CN', name: 'China'}, | ||
{code: 'RU', name: 'Russia'}, | ||
{code: 'DE', name: 'Germany'}, | ||
{code: 'CA', name: 'Canada'}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space inside { missing.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
Space inside } missing.
spec/example_app/db/seeds.rb
Outdated
Country.create([ | ||
{code: 'US', name: 'USA'}, | ||
{code: 'CN', name: 'China'}, | ||
{code: 'RU', name: 'Russia'}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space inside { missing.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
Space inside } missing.
spec/example_app/db/seeds.rb
Outdated
|
||
Country.create([ | ||
{code: 'US', name: 'USA'}, | ||
{code: 'CN', name: 'China'}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space inside { missing.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
Space inside } missing.
spec/example_app/db/seeds.rb
Outdated
Country.destroy_all | ||
|
||
Country.create([ | ||
{code: 'US', name: 'USA'}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use 2 spaces for indentation in an array, relative to the first position after the preceding left parenthesis.
Space inside { missing.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
Space inside } missing.
@@ -10,6 +10,7 @@ class CustomerDashboard < Administrate::BaseDashboard | |||
orders: Field::HasMany.with_options(limit: 2), | |||
updated_at: Field::DateTime, | |||
kind: Field::Select.with_options(collection: Customer::KINDS), | |||
country: Field::BelongsTo.with_options(primary_key: :code, foreign_key: :country_code), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [91/80]
:name, | ||
] | ||
|
||
ATTRIBUTE_TYPES = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Freeze mutable objects assigned to constants.
030f1bf
to
d0a1010
Compare
@@ -0,0 +1,4 @@ | |||
class Country < ActiveRecord::Base | |||
validates :code, presence: true | |||
validates :name, presence: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe do:
validates :code, :name, presence: true
class CreateCountries < ActiveRecord::Migration | ||
def change | ||
create_table :countries do |t| | ||
t.string :code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t.string :code, null: false, index: { unique: true }
That way you don't need the add_index
at the bottom. Also, since you're validating at the application level, these should be null: false
as well.
spec/example_app/db/seeds.rb
Outdated
Country.create(code: "CA", name: "Canada") | ||
Country.create(code: "CN", name: "China") | ||
Country.create(code: "RU", name: "Russia") | ||
Country.create(code: "AU", name: "Australia") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These could fail silently for a developer. Why not:
Country.create! [
{ code: "US", name: "Trump Temptations: The Billionaire & The Bellboy" },
{ code: "CA", name: "Canada" },
{ code: "CN", name: "China" },
{ code: "RU", name: "Russia" },
{ code: "AU", name: "Australia" }
]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, good point, but should we also add create-bang to other models in seeds.rb, i did create
to preserve uniformity. Also i'll better stick with old definition of US 🤣
spec/example_app/db/seeds.rb
Outdated
|
||
100.times do | ||
name = "#{Faker::Name.first_name} #{Faker::Name.last_name}" | ||
Customer.create( | ||
name: name, | ||
email: Faker::Internet.safe_email(name), | ||
country: Country.first, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This iterates 100 times. Maybe do:
country = Country.first
customers = Array.new(100) do
{
name: Faker::Name.name,
email: Faker::Internet.safe_email(name),
country: country
}
end
Customer.create!(customers)
Array.new
is faster than Integer#times
; best practice to always use Array.new
. Also, you don't have to call Customer.create
100 times, just once with an array for it to iterate over. We don't need this blazing fast. It's not inserting 2,000 records. However, we nearly made it do an extra 100 queries with Customer.first
instead of just one. We could actually make it even simpler with taking the data returned from our Country.create!
and sampling from there.
spec/example_app/db/seeds.rb
Outdated
{ code: "CA", name: "Canada" }, | ||
{ code: "CN", name: "China" }, | ||
{ code: "RU", name: "Russia" }, | ||
{ code: "AU", name: "Australia" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put a comma after the last item of a multiline array.
1445eb6
to
7e2d03f
Compare
@BenMorganIO let me know if there is something we need to make/improve |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure of the best way to solve this, but I think this is in the right direction.
spec/lib/fields/belongs_to_spec.rb
Outdated
foreign_key: "customers_uuid", | ||
) | ||
field = association.new(:customers, [], :show) | ||
expect(field.permitted_attribute).to eq("customers_uuid") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we break up the phases of this test with newlines? (https://robots.thoughtbot.com/four-phase-test)
spec/lib/fields/belongs_to_spec.rb
Outdated
|
||
describe "foreign_key option" do | ||
it "determines what foreign key is used on the relationship for the form" do | ||
association = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this line spacing is a bit awkward, what about
association = Administrate::Field::BelongsTo.with_options(
foreign_key: "customers_uuid",
)
lib/administrate/field/belongs_to.rb
Outdated
@@ -8,7 +8,7 @@ def self.permitted_attribute(attr) | |||
end | |||
|
|||
def permitted_attribute | |||
self.class.permitted_attribute(attribute) | |||
foreign_key || self.class.permitted_attribute(attribute) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I found this whole permitted_attribute
instance method calling a class method thing to be hard to follow and reason about. How would you feel about renaming class level implementations of permitted_attribute
to like default_attribute
or something like that? Or we could add an instance level default_attribute
method and put that here instead of calling a class method as a default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jcmorrow i ended up with
def foreign_key
options.fetch(:foreign_key, :"#{attribute}_id")
end
on the instance level of BelongsTo, i found dangerous to rewrite permitted_attributes
because it's used by BaseDashobard and Deffered classes.
@@ -24,6 +24,10 @@ def associated_class_name | |||
def primary_key | |||
options.fetch(:primary_key, :id) | |||
end | |||
|
|||
def foreign_key | |||
options.fetch(:foreign_key, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a huge fan of the way this reads in combination with line 25 above. Line 25 is handing you a default if not specified (which is what I would expect), but foreign_key
is instead returning nil
, and then allowing permitted_attribute
to implement the default behavior for a foreign_key
, but it's not clear from this line that that is what is going on. Does that make sense?
fc45f8f
to
cd0f445
Compare
469a6dd
to
e866000
Compare
CircleCI fails with:
i don't understand why this happening... |
spec/example_app/db/schema.rb
Outdated
|
||
# These are extensions that must be enabled in order to support this database | ||
enable_extension "plpgsql" | ||
|
||
create_table "countries", force: :cascade do |t| | ||
t.string "code" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't you make this null: false
in your migration?
25f3e3c
to
8a3d8a8
Compare
8a3d8a8
to
14f93e0
Compare
14f93e0
to
769aa38
Compare
Hi @iarie! I think this is almost good to go. Do you think you'd be able to document this in the |
f684c8f
to
6f6c12c
Compare
lib/administrate/base_dashboard.rb
Outdated
field = self.class::ATTRIBUTE_TYPES[key] | ||
|
||
next key if association_classes.include?(field) | ||
key if association_classes.include?(field.try :deferred_class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add parentheses to nested method call field.try :deferred_class.
@@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base | |||
def index | |||
search_term = params[:search].to_s.strip | |||
resources = Administrate::Search.new(resource_resolver, search_term).run | |||
resources = resources.includes(*resource_includes) if resource_includes.any? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [82/80]
@@ -1,4 +1,7 @@ | |||
#{$all-buttons}, | |||
button, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid qualifying attribute selectors with an element.
lib/administrate/base_dashboard.rb
Outdated
field = self.class::ATTRIBUTE_TYPES[key] | ||
|
||
next key if association_classes.include?(field) | ||
key if association_classes.include?(field.try :deferred_class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add parentheses to nested method call field.try :deferred_class.
@@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base | |||
def index | |||
search_term = params[:search].to_s.strip | |||
resources = Administrate::Search.new(resource_resolver, search_term).run | |||
resources = resources.includes(*resource_includes) if resource_includes.any? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [82/80]
@@ -1,4 +1,7 @@ | |||
#{$all-buttons}, | |||
button, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid qualifying attribute selectors with an element.
6f6c12c
to
e640768
Compare
require "administrate/base_dashboard" | ||
|
||
class CountryDashboard < Administrate::BaseDashboard | ||
ATTRIBUTES = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use %i or %I for an array of symbols.
require "administrate/base_dashboard" | ||
|
||
class CountryDashboard < Administrate::BaseDashboard | ||
ATTRIBUTES = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use %i or %I for an array of symbols.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nickcharlton done! And should i fix that dashboard attributes definition according to Hound?
3a570eb
to
9c8580b
Compare
9c8580b
to
d715683
Compare
rebased against master |
d715683
to
432a59e
Compare
This looks great! Could I get you to fix up those Hound warnings? I'd done that on a recent one I'd merged in, so it'd be good to start doing that. |
@nickcharlton fixing that syntax in example_app i thought should we also remake dashboard generators to rely on hound's syntax( add symbols %i array and freeze stuff)? Not here, in another PR? Not so important ofc :) |
Mmm. As they're not related to this PR, we should fix them up in another. |
gemfiles/.bundle/config
Outdated
@@ -0,0 +1,2 @@ | |||
--- | |||
BUNDLE_RETRY: "1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't notice this before; is this important for this PR or do you think it's better excluded?
ATTRIBUTES = %i( | ||
code | ||
name | ||
).freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we put this all on one line?
|
||
100.times do | ||
countries = Country.create! [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be indented inside this block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nickcharlton Sorry, i don't understand what do you mean.
Something wrong with brackets?
I can separate attributes declaration from .create!
like this:
country_attributes = [
{ code: "US", name: "USA" },
{ code: "CA", name: "Canada" },
{ code: "CN", name: "China" },
{ code: "RU", name: "Russia" },
{ code: "AU", name: "Australia" },
]
countries = Country.create!(country_attributes)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, oops! Apparently I didn't read the diff correctly.
gemfiles/.bundle/config
Outdated
@@ -0,0 +1 @@ | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, git still seems to think this file exists (but with just a blank line). Could you remove it completely?
Add country code to customers in example_app to show how it works
- add fetch default foreign_key to Field::BelongsTo - style fixes and specs
ada91e9
to
7c5964a
Compare
Excellent, thank you! Merging now. |
curious - why not use reflections to get the foreign key of a relation? |
@dan-ding - I think you are right, and we just didn't think of it at the time. |
#777
foreign_key
option in associative fields