don't works cancan ability for belongs_to model - ruby-on-rails-3

I have some problem with using CanCan gem.
I have ability.rb file:
if user.nil?
can :read, :all
elsif user.admin?
can :manage, Publication
else
can [:read, :create], Publication
can [:update, :destroy], Publication, :user_id => user.id
end
And it is publication.rb:
attr_accessible :content,:title
belongs_to :user
validates :user_id, presence: true
validates :title, presence: true, length: { maximum: 140 }
validates :content, presence: true, length: { minimum: 240 }
default_scope order: 'publications.created_at DESC'
And it is index.html.erb for publications:
<% #publications.each do |publicate| %>
<h3><%= publicate.title %></h3>
<% if can? :update, :destroy, Publication %>
<%= link_to "Update", edit_publication_path(publicate) %>
|<%= link_to " delete", publicate, method: :delete,
data: { confirm: "Are you sure?" } %>
<% end %>
<% end %>
And it's don't show delete and Update links, and if it's admin or logined user.
But if I change in ability.rb:
elsif user.admin?
can :manage, Publication
Publication to User, it's works, and I see links delete in user view:
<% #users.each do |user| %>
<li>
<%= link_to user.username, user %>
<% if can? :destroy, user %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "Are you sure?" } %>
<% end %>
</li>
<% end %>
And user.admin can :manage, :all , it's works too, and with users, and with publications. Why CanCan ignore Publication ability?

Please read:
Checking Abilities
https://github.com/ryanb/cancan/blob/master/lib/cancan/ability.rb#L56
and you should see why your conditional
can? :update, :destroy, Publication
is incorrect. Your action is :update and your subject is :destroy, and your third argument, Publication, is basically being ignored.

Related

Rails 3 - how to assign the value to nested attributes before calling save in update action

Models associations are
document.rb
has_many :sections
accepts_nested_attributes_for :sections, :allow_destroy => :true, :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
section.rb
belongs_to :document
has_many :paragraphs, :dependent => :destroy
has_many :contents :through => :paragraphs
validates :user_id, :presence => { :message => "Must be filled" }
paragraph.rb
attr_accessible :user_id, :section_id, :content_id
belongs_to :section
belongs_to :content
validates :user_id, :section, :content, :presence => { :message => "Must be filled" }
paragraphs table just like a intermediate table for sections and contents and I want to save records in documents, sections and paragraphs table using single submission.
So I designed form as like
_form.html.erb
<%= form_for #document, :validate => true do |f| %>
<%= f.error_messages %>
<%= f.text_field :name %>
<% f.fields_for :sections do |builder| %>
<%= builder.text_field :name %>
<%= builder.select :content_ids .... {:multiple => true} %>
<% end %>
<% end %>
example parameters when submiting the form
{"document"=>{"name"=>"sdf", "sections_attributes"=>{"0"=>{"name"=>"sdf", "description"=>"sdf", "_destroy"=>"0", "content_ids" => ["1", "2"]}}, "commit"=>"Update Document", "id"=>"3"}
In additionally, I am updating current_user's id to user_id column of paragraphs table.
update
#document = Document.find(params[:id])
#document.attributes = params[:document]
#document.sections.each {|section|
section.user_id = current_user.id
section.paragraphs.each {|paragraph| paragraph.user_id = current_user.id}
}
if #document.save!
# success
else
render :action => 'edit'
end
I got "Validation failed: User Must be filled".
Is validation triggered when assigning attributes using object.attributes= as above
How to assign the value to user_id in paragraph object before calling save method
Might help.
<%= f.hidden_field :user_id, value: current_user.id %>

How to validate password with confirm password [Rails 3.2]

How to validate password with confirm password in rails 3.2
my code not work
you can tell where my error
I've tried many variations changing the code in the controller.
Password saves but not validated to the password confirm field and password field.
help me please, help me )))
views
<%= form_for :password, :url => { :action => "change_password" }, :id => #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save", :class => "button blue" %>
<% end %>
User Controller
def change_password
#page_title = "Changing Zetfon account password"
#user = current_user
if request.post?
#user.password = Digest::SHA1.hexdigest(params[:password][:password])
if #user.save
redirect_to :action => 'profile'
flash[:status] = "Your password was changed. Next time you sign in use your new password."
else
flash[:status] = _('Your password not changed')
render :action => "change_password"
end
end
end
User Model
validates_confirmation_of :password
attr_accessible :password_confirmation
attr_accessor :password
add the following line to your model
validates :password, confirmation: true
Is it too late to simply use has_secure_password? You can learn about it in this RailsCast:
http://railscasts.com/episodes/270-authentication-in-rails-3-1
I'm not sure why you have if request.post?. Isn't that already determined by your route?
According to the documentation for validates_confirmation_of, I think you might need to add:
validates_presence_of :password_confirmation, :if => :password_changed?
Here's the documentation:
http://apidock.com/rails/ActiveModel/Validations/HelperMethods/validates_confirmation_of
The documentation seems to indicate that you don't need attr_accessible :password_confirmation either.
I hope that helps.

Can't mass-assign protected attributes: asset

I followed the tutorial screencast over here: http://www.emersonlackey.com/article/rails-paperclip-multiple-file-uploads. I want my model have multiple pictures upload show up.
I have examined carefully every steps, the most common issue is forget to add assets_attributes to attr_accessible, I have done that. Another issues might bbe forgot to add ID to asset model, i done that too. However, I still have trouble understanding why it happen.
Can't mass-assign protected attributes: asset in app/controllers/posts_controller.rb:24:in `update'
I have already add list of all attributes for a Post to post model. Like:
class Post < ActiveRecord::Base
attr_accessible :name, :content, :assets_attributes
validates :user_id, presence: true
belongs_to :user
has_many :assets
accepts_nested_attributes_for :assets, :allow_destroy => true
default_scope order: 'posts.created_at DESC'
end
Here is the post_controller.rb file:
def edit
#post = Post.find(params[:id])
5.times { #post.assets.build }
end
def update
#post = Post.find(params[:id])
if #post.update_attributes(params[:post])
redirect_to #post, :notice => "Post has been updated."
end
def create
post = current_user.posts.build(params[:post])
if post.save
flash[:success] = "post created success!"
redirect_to #post
else
#feed_items = []
flash[:failure] = "post created fail!"
redirect_to root_path
end
end
def new
#post = current_user.posts.new #if signed_in?
5.times { #post.assets.build }
end
Here is the template file:
<%= simple_form_for(#post, :html => {:multipart => true}) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :content %>
<%= f.text_field :content %>
<%= f.simple_fields_for :assets, :html => { :multipart => true } do |asset_fields| %>
<% if asset_fields.object.new_record? %>
<P><%= asset_fields.file_field :asset %> </P>
<% end %>
<% end %>
<%= f.simple_fields_for :assets, :html => { :multipart => true } do |asset_fields| %>
<% unless asset_fields.object.new_record? %>
<P><%= link_to image_tag(asset_fields.object.asset.url(:thumb)), asset_fields.objects.asset.url(:original) %>
<%= asset_fields.check_box :_destroy %></P>
<% end %>
<% end %>
Below is asset.rb:
class Asset < ActiveRecord::Base
belongs_to :post
has_attached_file :asset,
:style => { :large => "640x480", :medium => "300x300", :thumb => "100x100"} ,
:path => ":rails_root/public/system/posts/images/:id/:style/:filename",
:url => "/system/posts/images/:id/:style/:filename"
end
Can someone give me some hint ? Thanks a lot!
Your Asset model needs to have attr_accessible on it too - specifically for the asset field.

Rails: Validation for a simple_form using has_many relationship (e.g. Person, Phone)

I'm struggling getting the desired validation with nested models within a simple_form. You'll be able to see from the models below a Person can have many Phone's, the desired behaviour is to present edit fields for any existing numbers plus an additional one should for a new number, if this new number isn't filled in by the user then it's just ignore and not saved in the database. I also want to achieve similar with Email.
When landing on the /people/:id/edit page this blank field is being prematurely validated and producing visible errors on the form before submitting. It doesn't do this when visiting /people/:id/new page; I'm assuming that this is because new_record? returns true for the user model on the new page? In reading a similar post I added on: :save as a parameter to validates on the Phone model although this just allowed blank records into the database, perhaps because this isn't relevant when the user model is saving the record?
class Person < ActiveRecord::Base
belongs_to :company
has_many :phones, :as => :phoneable
has_many :emails, :as => :emailable
has_many :addresses, :as => :addressable
attr_accessible :first_name, :job_title, :last_name, :prefix, :phones_attributes, :emails_attributes, :addresses_attributes, :company_id
accepts_nested_attributes_for :phones, allow_destroy: true, reject_if: proc { |attributes| attributes['number'].blank? }
accepts_nested_attributes_for :emails, allow_destroy: true, reject_if: proc { |attributes| attributes['email'].blank? }
accepts_nested_attributes_for :addresses, allow_destroy: true, reject_if: :all_blank
validates :first_name, :last_name, presence: true
def to_s
"#{first_name} #{last_name}"
end
end
class Phone < ActiveRecord::Base
belongs_to :phoneable, polymorphic: true
attr_accessible :number, :phone_type
validates :number, :phone_type, presence: true, on: :save # as suggested in a similar post, just allows blank records into database.
def to_s
"#{phone_type}: #{number}"
end
end
With both the new and edit controller I'm creating a new instance of each of these models so that they show up on the form. #person is loaded in the controller using load_and_authorize_resource as part of cancan.
def new
#person.phones << Phone.new
#person.emails << Email.new
end
Here is the partial view for the form:
<%= simple_form_for #person, :html => { :class => 'form-horizontal' } do |f| %>
<fieldset id="<%= controller.action_name.capitalize %>_person">
<legend><%= controller.action_name.capitalize %> Person</legend>
<%= f.input :prefix %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :job_title %>
<%= f.association :company, :prompt => "Select associated company..." %>
<%= f.simple_fields_for :phones do |phone| %>
<%= phone.input :phone_type, :collection => %w(Work Home Mobile Fax Other), :default => "Work" %>
<%= phone.input :number %>
<% end %>
<%= f.simple_fields_for :emails do |email| %>
<%= email.input :email_type, :collection => %w(Work Home Other), :default => "Work" %>
<%= email.input :email %>
<% end %>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
people_path, :class => 'btn' %>
</div>
</fieldset>
<% end %>
Many thanks for any help in advance :-)

Rails - Nested Model Fails to Save

I'm rather new to Rails and I'm writing a signup form that includes nested models. When I submit the form, the user is saved just fine, but the nested model does not save anything to the Subscription db, and the console throws no errors.
I sincerely hope I'm not missing something insanely obvious, and I appreciate any tips you can share. Thanks!
Here is the code-
Models:
class Plan < ActiveRecord::Base
attr_accessible :posts, :name, :price
has_many :users
end
class User < ActiveRecord::Base
belongs_to :plan
has_many :events
has_one :subscription, :autosave => true
accepts_nested_attributes_for :subscription
attr_accessible :subscription_attributes
def save_with_payment
if valid?
customer = Stripe::Customer.create(
email:email,
plan: plan_id,
card: stripe_card_token )
self.stripe_customer_token = customer.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
end
class Subscription < ActiveRecord::Base
attr_accessible :plan_id, :status, :user_id
belongs_to :user
end
This is the User controller:
def new
#user = User.new
plan = Plan.find(params[:plan_id])
#user = plan.user
#user.build_subscription
end
def create
#user = User.new(params[:user])
if #user.save_with_payment
sign_in #user
flash[:success] = "Welcome to the SendEvent!"
redirect_to #user
else
render 'new'
end
end
This is the form:
<%= form_for #user, :html => {:class => "form-inline"} do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="control-group">
<%= f.label :name, :class => "control-label" %>
<%= f.text_field :name %>
</div>
# A few more fields here and...
# The nested model:
<%= f.fields_for :subscription do |builder| %>
<%= builder.hidden_field :status, :value => true %>
<% end %>
<%= f.submit "Create my account", class: "btn btn-large btn-primary", id: "submitacct" %>
<% end %>
Sample app from RailsCasts
RailsCasts Episode #196: Nested Model Form (revised)
Maybe help you.