Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,34 @@ editable @model, :enabled, source: source, classes: classes, class: "label"
%h1= editable [picture.gallery, picture], :name, nested: :translations, nid: picture.translation.id
```

* **nest_def (takes precedence to the two options above)** - Hash or array of hash that describes the nestd attributes

```ruby
class Group << ActiveRecord::Base
has_many :users
end

class User << ActiveRecord::Base
# name: string
belongs_to :group
has_many :posts
end

class Post << ActiveRecord::Base
# title: string
belongs_to :user
end


%h1= editable @group, :name, nest_def: {users: @user.id}
#=> the params will be {group: {users_attributes: {id: <@user.id>, name: <name>}}}

%h1= editable @group, :title, nest_def: [{users: @user.id}, {posts: @post.id}]
#=> the params will be {group: {users_attributes: {id: <@user.id>, posts_attributes: {id: <@post.id>, title: <title>} }}
# Note that the order of array matters.

```

### Authorization

Add a helper method to your controllers to indicate if `x-editable` should be enabled.
Expand Down
59 changes: 49 additions & 10 deletions lib/x-editable-rails/view_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,29 @@ def editable(object, method, options = {})

url = options.delete(:url){ polymorphic_path(object) }
object = object.last if object.kind_of?(Array)
value = options.delete(:value){ object.send(method) }
source = options[:source] ? format_source(options.delete(:source), value) : default_source_for(value)
classes = format_source(options.delete(:classes), value)
error = options.delete(:e)
html_options = options.delete(:html){ Hash.new }

if xeditable?(object)
model = object.class.model_name.param_key
nid = options.delete(:nid)
nested = options.delete(:nested)
title = options.delete(:title) do
klass = nested ? object.class.const_get(nested.to_s.classify) : object.class
model = object.class.model_name.param_key
nid = options.delete(:nid)
nested = options.delete(:nested)
nest_def = options.delete(:nest_def)

deepest_obj = nest_def ? dig_nested_obj(object, nest_def) : object
value = options.delete(:value){
nest_def ? deepest_obj.send(method) : object.send(method)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary spacing detected.
Operator ? should be surrounded by a single space.

}
source = options[:source] ? format_source(options.delete(:source), value) : default_source_for(value)
classes = format_source(options.delete(:classes), value)


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra blank line detected.

title = options.delete(:title) do
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary spacing detected.
Operator = should be surrounded by a single space.

if nest_def
klass = nest_def.is_a?(Array) ? object.class.const_get(nest_def.last.keys.first.to_s.classify) : object.class.const_get(nest_def.keys.first.to_s.classify)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [170/80]

else
klass = nested ? object.class.const_get(nested.to_s.classify) : object.class
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [92/80]

end
klass.human_attribute_name(method)
end

Expand All @@ -54,13 +65,14 @@ def editable(object, method, options = {})
type: type,
model: model,
name: method,
value: ( type == 'wysihtml5' ? Base64.encode64(output_value) : output_value ),
value: ( type == 'wysihtml5' ? Base64.encode64(output_value) : output_value ),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line is too long. [93/80]
Space inside parentheses detected.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.

placeholder: placeholder,
classes: classes,
source: source,
url: url,
nested: nested,
nid: nid
nid: nid,
nest_def: nest_def
}.merge(options.symbolize_keys)

data.reject!{|_, value| value.nil?}
Expand Down Expand Up @@ -145,6 +157,33 @@ def default_source_for(value)
end
end

def dig_nested_obj(obj, nested)
case(nested)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after keyword case is missing.

when Array
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent when as deep as case.

obj = nested.inject(obj){|memo, n|
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using {...} for multi-line blocks.

attr = n.keys.first
id = n.values.first
case(memo.class.reflect_on_association(attr))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after keyword case is missing.

when ActiveRecord::Reflection::HasOneReflection
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent when as deep as case.

memo = memo.send(attr)
when ActiveRecord::Reflection::HasManyReflection
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent when as deep as case.

memo = memo.send(attr).find_by(id: id)
end
memo
}
when Hash
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent when as deep as case.

attr = nested.keys.first
id = nested.values.first
obj = case(obj.class.reflect_on_association(attr))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after keyword case is missing.

when ActiveRecord::Reflection::HasOneReflection
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent when as deep as case.

obj.send(attr)
when ActiveRecord::Reflection::HasManyReflection
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent when as deep as case.

obj.send(attr).find_by(id: id)
end
end
return obj
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant return detected.

end

# helper method that take some shorthand source definitions and reformats them
def format_source(source, value)
formatted_source = case value
Expand Down
25 changes: 24 additions & 1 deletion vendor/assets/javascripts/editable/rails/editable_form.js.coffee
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
unless EditableForm
build_nested_param = (attr_to_update, updated_value, nest_def)->
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function arrows (-> and =>) must be spaced properly

ret = {}
last = ret
if(Array.isArray(nest_def))
for obj in nest_def
attr = Object.keys(obj)[0]
key = attr + "_attributes"
id = obj[attr]
last[key] = {id: id}
last = last[key]
else if (typeof nest_def == "object" && nest_def != null)
attr = Object.keys(nest_def)[0]
key = attr + "_attributes"
id = nest_def[attr]
last[key] = {id: id}
last = last[key]

last[attr_to_update] = updated_value
ret

EditableForm = $.fn.editableform.Constructor
EditableForm.prototype.saveWithUrlHook = (value) ->
originalUrl = @options.url
model = @options.model
nestedName = @options.nested
nestedId = @options.nid
nestDef = @options.nestDef
nestedLocale = @options.locale

@options.url = (params) =>
Expand All @@ -20,7 +41,9 @@ unless EditableForm

obj = {}

if nestedName
if nestDef
obj = build_nested_param(myName, myValue, nestDef)
else if nestedName
nested = {}
nested[myName] = myValue
nested['id'] = nestedId
Expand Down
14 changes: 12 additions & 2 deletions vendor/assets/javascripts/editable/rails/error_handling.js.coffee
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
$.fn.editable.defaults.error = (response, newValue) ->
field_name = $(this).data("name")
nested = $(this).data('nested')
if(Array.isArray(nested))
keys = nested.map((obj)-> Object.keys(obj)[0])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function arrows (-> and =>) must be spaced properly

keys.push($(this).data("name"))
field_name = keys.join(".")
else if (typeof nested == "object" && nested != null)
key = Object.keys(nested)[0]
field_name = key + "." + $(this).data("name")
else
field_name = $(this).data("name")

error_msgs = response.responseJSON.errors[field_name]
error_msgs.join "; "
error_msgs.join "; "