I have a rails app that has articles that and the user can add links and reviews as nested attributes.
I saw in the paper_trail https://github.com/airblade/paper_trail/ documentation that this is not covered by that gem. How would I go about setting up undo functionality so that nested attributes or has_many associations are restored/updated when a user clicks undo?
I think if you hook in a "destroy" post to the undo button it will at least remove the links if they click undo. Basically you pass a hash with the special _destroy key it will remove the nested model records.
From Rails 3 docs here:
class Member < ActiveRecord::Base
has_one :avatar
accepts_nested_attributes_for :avatar, :allow_destroy => true
end
Now, when you add the _destroy key to the attributes hash, with a value that evaluates to true, you will destroy the associated model:
member.avatar_attributes = { :id => '2', :_destroy => '1' }
member.avatar.marked_for_destruction? # => true
member.save
member.reload.avatar # => nil
Related
Am able to manage habtm as per follow, and I wanted a better way for this
I have habtm between User and Tag on Rails 3, aa 0.5.1
Tag name is uniq
f.input :tags, :label => 'Assign existing tag'
# this above allows to select from existing tags, but cannot allow to create one
f.has_many :tags, :label => 'Add new tags, modify existings' do |ff|
ff.input :name
ff.input :_destroy, :as => :boolean
end
# this above allows to create new one but not allow to specify existing one
# if we specify existing one, uniqueness wont let create this one, neither existing get used
# and throws validation error
any hints?
Adding my models
class User < ActiveRecord::Base
has_and_belongs_to_many :tags
scope :tagged_with, lambda {|tags| joins(:tags).where("tags.name" => tags)}
accepts_nested_attributes_for :tags, :allow_destroy => true
end
class Tag < ActiveRecord::Base
has_and_belongs_to_many :users
validates :name, :uniqueness => { :case_sensitive => false }
end
Try this,
f.label => 'Assign existing tag'
f.select :tags, Tag.all.map{|t| [t.tag_name, t.id]}, {:prompt => "Select Tag name" }
this above allows to select from existing tags, don't have option to create one
For the Second thing add this line in the model,
validates :tags, :uniqueness => {:scope => :tag_name}
here the :tag_name is your name of the fieldname. This throw an error if the tag name already exists when you create a duplicate.
It's just an idea as per your question. This won't be your exact answer because your specification is not enough to give you the exact answer.
so I have a tricky issue here I'm not sure how to solve.
I have a Provider model that has_many :educational_affiliations
EducationalAffiliation belongs_to :institution & belongs_to
:provider
I have about 9000 universities in my database, so I'm using the handy-dandy rails3-jquery-autocomplete gem to give me type-ahead support. That's all working great - on TOP of that I'm using cocoon to support the nesting of the :educational_affiliations form inside of the provider's edit form.
So here's where the issue comes — This works great for submitting new affiliation records, (I'm using some jquery to set the :institution_id on the :educational_affiliations_attributes object, works great)
BUT when I return to edit this later, of course the :institution_name isn't populated, because it's not part of the :educational_affiliations model, it's in the :institution model.
Here's what I just tried in my :educational_affiliations, which I assume is the right solution:
class EducationalAffiliation < ActiveRecord::Base
attr_accessible :degree, :graduation_year, :honors, :institution_name, :institution_id, :provider_id
belongs_to :institution
belongs_to :provider
# attr_accessor :institution_name
validates :institution_id, :graduation_year, :provider_id, :degree, presence: true
def institution_name
Institution.find(institution_id).name
end
end
(i had it working for saving using the attr_accessor, but I've commented it out for now)
So when I render the edit view with the above, I get a ActiveRecord::RecordNotFound: Couldn't find Institution without an ID error — but when I open a debugger on that statement, the model DOES seem to know the institution_id...so confused why it doesn't pick it up.
Am I just doing this in the worst way possible? I assume there's a dumb solution.. :)
Here's the partial that needs the name populated:
.nested-fields
= f.input :institution_name, url: autocomplete_institution_name_data_path, as: :autocomplete, :input_html => {:id_element => '#provider_educational_affiliations_institution_id'}
= f.input :institution_id, as: :hidden
= f.input :provider_id, as: :hidden, input_html: { value: current_provider.id }
= link_to_remove_association "Remove Degree", f
Instead of the virtual attribute method, try the following to define the attribute:
delegate :name, :name=, :to => :institute, :prefix => true
Here is an example of my problem.
I have a 'Room' model:
class Room < ActiveRecord::Base
has_many :items, :inverse_of => :room
accepts_nested_attributes_for :items
end
And I have an 'Item' model:
class Item < ActiveRecord::Base
belongs_to :room, :inverse_of => :items
validates :some_attr, :uniqueness => { :scope => :room}
end
I want to validate the uniqueness of the :some_attr attribute of all the Items which belongs to a certain room.
When I try to validate the items, I get this error:
TypeError (Cannot visit Room)
I cannot set the scope of the validation to be :room_id since the items are not saved yet so the id is nil. I also want to prevent using custom validators in the 'Room' model.
Is there any clean way to do it in Rails? I also wonder if I set the :inverse_of option correctly...
I don't see anything wrong with how you're using inverse_of.
As for the problem, in a similar situation I ended up forcing a uniqueness constraint in a migration, like so
add_index :items, [ :room_id, :some_attr ], :unique => true
This is in addition to the AR-level validation
validates_uniqueness_of :some_attr, :scope => :room_id
(I'm not sure if it's valid to use the association name as a scope, won't the DB adapter raise an exception when trying to refer to the non-existent room column in a query?)
I have the following in my user model
class User < ActiveRecord::Base
has_many :gym_users
attr_accessible :gym_users_attributes, :gym_users
accepts_nested_attributes_for :gym_users, :reject_if => lambda { |a| a[:role_id].blank? }
end
This correctly rejects the gym_user model if the role_id is not present, the problem is it still creates the user and simply doesn'
t create the gym_user. Is there a way to make it not create or delete the user when the gym_user is rejected?
You can add
validates_associated :gym_users
to your User model and move validation from reject_if to GymUsers model
validates_presence_of :role_id
Add validates :gym_users, :presence => true to your User model
I have a model that allows a User to mark other Users as Favorites.
This HABTM relationship is defined in the User model:
class User < ActiveRecord::Base
has_and_belongs_to_many :favorites, :class_name => "User", :join_table => "favorites", :association_foreign_key => "favorite_id", :foreign_key => "user_id"
end
The FavoritesController only requires three actions (index, create,
destroy) to manage a User's Favorites.
Rule: Only an authenticated user (current_user) is allowed to manage
their Favorites.
Initially, I tried to represent this rule in the authorization_rule.rb
file:
# allow authenticated user to update profile
has_permission_on :users, :to => :change do
if_attribute :id => is { user.id }
has_permission_on :favorites, :to => [:index,:create,:destroy]
end
This didn't work, probably because the Favorite doesn't have an
explicit model (i.e. favorite.rb). Though I could be wrong about
this.
It seems like the correct approach would be to represent the rule in
the FavoritesController:
filter_access_to :all, :nested_in => :users
...
But I'm not certain how to represent the rule properly here.
Assistance is really appreciated.
** edit **
It was suggested that I use a context to control access in this situation:
setting permissions for a no-model controller .
I tried modifying the FavoritesController:
filter_access_to :all, :context => :favorites
This change had no effect.
** /edit **