I am currently working on a rails based application to manage orders. (Rails 4.1.5 and ActiveAdmin)
I have these models:
class Customer < ActiveRecord::Base
has_many :estimates
has_many :orders
accepts_nested_attributes_for :estimates, :allow_destroy => true
accepts_nested_attributes_for :orders, :allow_destroy => true
end
class Order < ActiveRecord::Base
belongs_to :customer
has_many :line_items, as: :cartable
accepts_nested_attributes_for :line_items, :allow_destroy => true
end
class Estimate < ActiveRecord::Base
belongs_to :customer
has_many :line_items, as: :cartable
accepts_nested_attributes_for :line_items, :allow_destroy => true
end
What I want to do is to create a new Order based on the Estimate record. The things work if I create a new order and show the edit page with:
member_action :confirm, :method => :get do
old_estimate = Estimate.find(params[:id])
new_estimate = Order.create(old_estimate.attributes.merge({:id => nil, :created_at =>
nil,:updated_at => nil}))
old_estimate.line_items.each do |li|
new_estimate.line_items.create(li.attributes.merge({:id => nil, :created_at => nil,
:updated_at => nil}))
end
redirect_to edit_customer_order_path(new_estimate.customer, new_estimate)
end
but I would like to use the "new" action and create the record only after it has been edited and confirmed.
I tried to use
redirect_to new_customer_order_path(old_estimate.customer, old_estimate.attributes)
and it will render the new form but without any parameters in it.
The params are in the URL but I got an "Unpermitted parameters:" in the log. All the params are permitted under Active Admin(either under other.rb and estimate.rb) as:
permit_params :id, :customer_id, :title, :edd, :total,
line_items_attributes: [:id, :cartable_id, :cartable_type, :product_type, :source_lang, :dest_lang, :unit_price, :total, :_destroy]
Anyone have any suggestion?
You can override the new action to set some default value in the form:
controller do
def new
record = YourActiveRecordModel.new #or find, if you pass id
record.some_attribute = some_value
new!
end
end
The corresponding input will be filled.
Related
How do I add the current user to the user_product table when saving a user's product.
I looked at some info online that shows that I can pass in a parameter to the build method, but this doesnt work. The error message is this "Can't mass-assign protected attributes: user_id"
Product controller:
def new
#product = Product.new
#product.user_products.build(:user_id => current_user)
respond_to do |format|
format.html # new.html.erb
format.json { render json: #product }
end
end
My models are: Product, User, User_Product
class Product < ActiveRecord::Base
attr_accessible :name, :issn, :category, :user_products_attributes
validates_presence_of :name, :issn, :category
validates_numericality_of :issn, :message => "has to be a number"
has_many :user_products
has_many :users, :through => :user_products
accepts_nested_attributes_for :user_products
end
class UserProduct < ActiveRecord::Base
attr_accessible :price
validates_presence_of :price
validates_numericality_of :price, :message => "has to be a number"
belongs_to :user
belongs_to :product
end
class user < ActiveRecord::Base
# devise authentication here
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :user_products, :dependent => :destroy
has_many :products, :through => :user_products
end
I suggest the following:
Product
has_many :preferences
has_many :users, :through => preferences
has_one :product_photo # if 1 per product
User
has_many :preferences
has_many :products, :through => :preferences
Preference
belongs_to :user
belongs_to :product
ProductPhoto
belongs_to :product
Whatever you do, make sure you pay attention to capitalization and pluralization as rails is pretty picky about that. If you don't get rails conventions right, the code will not work (and worse you will start writing hacks to get around the perceived 'problem'), for instance User_Product should be UserProduct (or Preference in my answer) not User_Product - for the class definition model name (references to it use lower case and underscore though).
So basically, my app contains users (model User) who have friends (unilateral access), and who also own lists.
What I'm trying to achieve here is when creating a new list, to provide it with "accessors", picked from the user's friends.
My code is heavily inspired from the following railscast on virtual attributes.
So, here comes my User and UserAccessor model (just the relevant parts) :
class User < ActiveRecord::Base
has_many :lists, :dependent => :destroy
has_many :friendships, :dependent => :destroy
has_many :friends, :through => :friendships
end
class UserAccessor < ActiveRecord::Base
belongs_to :accessor, :class_name => "User"
belongs_to :accessible_list, :class_name => "List"
end
My List model :
class List < ActiveRecord::Base
has_many :items
belongs_to :user
has_many :user_accessors, :foreign_key => "accessible_list_id", :dependent => :destroy
has_many :accessors, :class_name => "User", :through => :user_accessors
validates :title, :presence => true, :length => { :minimum => 1 }
attr_writer :authorized_users
after_save :add_accessors
def authorized_users
#authorized_users || self.accessors.map(&:username).join(' ')
end
private
def add_accessors
if #authorized_users
accessors = #authorized_users.split(' ').map do |username|
user = User.find_by_username(username)
if user
if self.user.inverse_friends.include? user
self.user_accessors.build(:accessor_id => user.id).accessor
end
end
end
end
end
end
The form used to create or update the list is the following one :
= simple_form_for [#user, #list] do |f|
= f.input :title, :label => "Titre"
= f.input :authorized_users, :label => "Authorized users", :hint => "Separated by spaces"
%p
= f.button :submit
So my problem comes from the fact that I don't know exactly how to create/update the accessors, my code self.user_accessors.build(:accessor_id => user.id).accessor definitely not working to fill it correctly.
I'm still quite a noob in rails (and ruby in general…), so I hope what I put there was relevant enough for you to help me! Thanks in advance!
I have started off by following this guide here Rails - Multiple Index Key Association
I have tried to add in :include to speed up the association but im getitng this error:
ActiveRecord::StatementInvalid in ItemsController#show
SQLite3::SQLException: no such column: links.item_id: SELECT "links".* FROM "links" WHERE ("links".item_id = 19)
here's what i have:
item.rb
class Item < ActiveRecord::Base
has_many :links, :dependent => :destroy, :uniq => true
belongs_to :category
belongs_to :user
is_sluggable :name
def links
Link.by_item(self)
end
link.rb
class Link < ActiveRecord::Base
belongs_to :item1, :class_name => 'Item', :foreign_key => :item1_id
belongs_to :item2, :class_name => 'Item', :foreign_key => :item2_id
belongs_to :user
validates_presence_of :item1_id
validates_presence_of :item2_id
validates_uniqueness_of :item1_id, :scope => :item2_id, :message => "This combination already exists!"
def self.by_item(item)
where("item1_id = :item_id OR item2_id = :item_id", :item_id => item.id)
end
end
items_controller.rb
def show
#item = Item.find_using_slug(params[:id], :include => [:category, :user, :links])
It works okay without :links inside :include. But otherwise I get the error.
From what I understand, the item_id is stored in the links table as item1_id or item2_id, which is why it cannot be found. Is there a workaround for this because I will be heavily referencing the links records. I am not so good with the SQL stuff.
Also unsure what's the best way to set up an Index
Willing to try out any advice. Thanks
The problem lies with the has_many :links association setup in Item. By default, this gets converted to a SQL query which looks for all links which have an item_id of the current Item. To override this default behavior, specify the find SQL yourself like this:
has_many :links, :dependent => :destroy, :uniq => true, :finder_sql => 'SELECT DISTINCT(*) FROM links WHERE item1_id = #{id} OR item2_id = #{id}'
Edit: It looks like defining #categories again in the task's create method did the trick of clearing up the error. Still working on actually having the category update when I submit the task, because right now it's ignoring it. Any ideas?
Hi all,
I'm trying to create a drop down list in my first Rails project in order to select from a list of categories for a task. I've used a Categorization model to link the Task model with a Category.
After some effort, I've gotten the drop down to show up properly on the new task form, but when I hit submit, the form gives the following error:
NoMethodError in Tasks#create
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map
Any help you could provide is really appreciated. Here is the code I'm using (excerpted for brevity)...
The relevant part of my new task form (HAML):
= f.fields_for :categorization do |sub|
= sub.label :name, 'Category'
= sub.collection_select(:category_id, #categories, :id, :name, :include_blank => 'Select a Category')
tasks_controller.rb:
def new
#task = Task.new
#categories = Category.all
end
def create
#task = current_user.tasks.build(params[:task])
if #task.save
flash[:success] = "Task created!"
redirect_to root_path
else
render 'new'
end
end
categorization.rb:
class Categorization < ActiveRecord::Base
belongs_to :task
belongs_to :category
validates :task_id, :presence => true
validates :category_id, :presence => true
end
category.rb:
class Category < ActiveRecord::Base
has_many :categorizations, :dependent => :destroy
has_many :tasks, :through => :categorizations
validates :name, :presence => true
end
task.rb
class Task < ActiveRecord::Base
attr_accessible :title, :body
has_many :categorizations, :dependent => :destroy
has_many :categories, :through => :categorizations
accepts_nested_attributes_for :categorizations
validates :title, :presence => true
validates :body, :presence => true
end
routes.rb:
resources :tasks
resources :categories do
member do
get :tasks
end
end
Any thoughts? Thank you so much for taking a look, and let me know if you need anything else to help.
Haidn
I think you're going to need to add the following line to your categorization.rb:
attr_accessible :category_id
Without that line, you cannot set the category_id in the build method you are using in tasks_controller.rb
Let me know if that fixes it for you!
OK, I'm going to try figuring out correctly implementing the save on my own, but I discovered the solution for my original problem, which was declaring #categories again in my Task create method. Hopefully that helps somebody!
I have the following model
class Project < ActiveRecord::Base
has_many :assignments, :conditions => {:deleted_at => nil}
has_many :members, :conditions => {:deleted_at => nil}
accepts_nested_attributes_for :members, :allow_destroy => true
end
class Member < ActiveRecord::Base
belongs_to :project
belongs_to :person
belongs_to :role
has_many :assignments, :dependent => :destroy, :conditions => {:deleted_at => nil}
accepts_nested_attributes_for :assignments, :allow_destroy => true
validates_presence_of :role_id
validates_presence_of :project_id
end
and I assume the controller will populate the member.project_id upon project.save for each nested member record. However, I get a validation error stating the project_id is blank.
My controller method:
def create
# #project is created in before_filter
if #project.save
flash[:notice] = "Successfully created project."
redirect_to #project
else
render :action => 'new'
end
end
Do I need to manually set the project_id in each nested member record? Or what is necessary for the controller to populate when it creates the member records?
Create the Member object like this:
#member = #project.members.build