ruby on rails - Refactor code to avoid circular logic in controller -


situation:

  • one form allows users select multiple quantities of items they'd request
  • this form posts 2 models, 1 parent: request, , child: items.
  • upon submit, 1 request created, several items created, depending on quantity indicated
  • to handle this, have 2 sets of params, 1 items, 1 requests

desired end state:

  • i not want item created without request nor request created without item
  • all errors present in form (whether it's not selecting @ least 1 item, or errors in attributes of request object) shown user once page re-rendered; i.e., error checking together

current hacky solution & complication:

  • currently, i'm checking in stages, 1) there quantities in items? if not, regardless of user may have put request attributes, page re-rendered (i.e., attributes request lost, validation errors shown). 2) once first stage passed, model validations kicks in, , if fails, new page re-rendered again

i've spent waaaaay long thinking this, , nothing elegant comes mind. happy hacky solution, love insights smarter people!

controller code (fat now, fix later)

def create  request_params @requestrecord = @signup_parent.requests.build  if @itemparams.blank?   @requestrecord.errors[:base] = "please select @ least 1 item"   render 'new' else   @requestrecord = @signup_parent.requests.create(@requestparams)   if @requestrecord.save     items_to_be_saved = []     @itemparams.each |item, quantity|     quantity = quantity.to_i       quantity.times         items_to_be_saved << ({:request_id => 0, :name => item })       end     end     item.create items_to_be_saved     flash[:success] = "thanks!"     redirect_to action: 'success'   else     render 'new'   end end end  def request_params   @requestparams = params.require(:request).permit(:detail, :startdate, :enddate)    @itemparams = params["item"]   @itemparams = @transactionparams.first.reject { |k, v| (v == "0") || (v == "")} end 

and in case it's helpful, snippet of view code generates params["item"]

          <% itemlist.each |thing| %>             <%= number_field_tag "item[][#{thing}]", :quantity, min: 0, placeholder: 0 %>             <%= label_tag thing %>             </br>           <% end %>           <!-- itemlist variable in controller populated list of items --> 

validations

when mention want errors returned @ same time, means need use rails' validations functionality.

this populates @model.errors object, can use on form this:

<% if @model.errors.any? %>   <ul>     <% @model.errors.full_messages.each |msg| %>       <li><%= msg %></li> 

i think problem you're trying use validations in controller. both against mvc principles & bad programming modularity. functionality require available validations features:


you may benefit using inverse_of create conditional validations; or using reject_if

reject_if

#app/models/request.rb class request < activerecord::base    accepts_nested_attributes_for :items, reject_if: proc { |attributes| attributes['an_item_param'].blank? #-> attributes "item" attributes } end 

this triggered if request created. i.e if request fails reason (validation issue), accepts_nested_attributes_for method not run, returning object appended errors

this used validate nested resources (i.e can't save item unless title attribute populated etc)

--

inverse_of

#app/models/request.rb class request < activerecord::base    has_many :items, inverse_of: :request    accepts_nested_attributes_for :items end  #app/models/item.rb class item < activerecord::base    belongs_to :request, inverse_of: :items    validates :title, presence: true, unless: :draft?     private     def draft?        self.request.draft #-> example we've used before :)    end end 

this more model-specific validations; allowing determine specific conditions. use if want save draft etc


Comments

Popular posts from this blog

google api - Incomplete response from Gmail API threads.list -

Installing Android SQLite Asset Helper -

Qt Creator - Searching files with Locator including folder -