Virtual attributes in Rails 4 from Rails 3 - ruby-on-rails-4

I am creating a Rails 4.10 app and I am using code from my Rails 3.2 app.
In this app I got a form where I add a virtual attribute called group_ids and then use after_save to add groups to a user.
In my 3.2 code:
attr_accessor :group_ids
after_save :add_groups
def add_groups
if group_ids.present?
self.assignments.user_groups.delete_all
group_ids.reject!(&:empty?)
group_ids.each do |group|
assignment = Assignment.new
assignment.assignable_id = group
assignment.assignable_type = "UserGroup"
assignment.backend_user_id = self.id
self.assignments << assignment
end
end
end
In my 4.10 code:
Controller:
params.require(:backend_user).permit(:firstname, :lastname, :group_ids)
How can I use the Add_groups method in 4.10?

Looking at your code, it seems that group_ids are not being whitelisted correctly in the controller code resulting in group_ids not being set which in turn would result in group_ids.present? condition returning false in your after_save callback. So, none of the statements gets executed in the callback.
To cut it short, after_save callback add_groups is getting executed but its not doing anything.
To resolve this, you should be whitelisting group_ids as an Array in your controller code:
params.require(:backend_user).permit(:firstname, :lastname, :group_ids => [])

Related

Pass locals from controller to active model serializer

I am trying to pass locals(prod: #product.id) to AMS in my controller, as follows:
#options_json = ActiveModel::SerializableResource.new(#option_types, prod: #product.id)
#options_json = #options_json.to_json(serialization_context: ActiveModelSerializers::SerializationContext.new(request), serialization_options: {prod: #product.id})
I am not sure whether to pass it during initialization or during call to to_json. Moreover I am unable to read this passed param in my OptionTypeSerializer. I've tried using options[:prod], serialization_options[:prod], serialization_opts[:prod] and a few different solutions that I found on stackoverflow, but none worked.
My AMS is pointed to master and in my gemfile.lock AMS version is active_model_serializers (0.10.0.rc5)
Also tried using:
#options_json = ActiveModel::SerializableResource.new(#option_types, serialization_context: ActiveModelSerializers::SerializationContext.new(request), prod: #product.id).to_json
but getting the value of instance_options[:prod] as null, although it is not null
Whenever I need to pass options into a serializer I do something like this:
# Controller
class CatalogPagesController < ApplicationController
# GET /catalog_pages/event/:id
def event
#catalog_pages = #event.catalog_pages
render json: #catalog_pages, index: true, each_serializer: Adm::CatalogPageSerializer
end
end
# Serializer
class CatalogPageSerializer < Adm::FormSerializer
attributes :id, :body, :catalog_page_templates
def include_catalog_page_templates?
return true unless #options[:index].present?
end
end
In this example I want to conditionally not return certain elements of JSON when coming from the index route.

Pundit::AuthorizationNotPerformedError attempting to adapt microposts to Devise/Pundit

I'm new to Rails and I'm working through Michael Hartl's excellent Rails Tutorial for a second time, this time I'm trying to adapt the chapter 11 and chapter 12 microposts to a simple Devise/Pundit application I'm working on. I am able to create microposts through the seed file and display them, but I'm getting an authorization error with Pundit when I actually try to create a new post through the site. The error I'm getting is:
Pundit::AuthorizationNotPerformedError in MicropostsController#create
My Microposts Controller looks like this:
class MicropostsController < ApplicationController
before_action :authenticate_user!
after_action :verify_authorized
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to current_user
else
#feed_items = []
flash[:danger] = "Unable to create micropost!"
end
end
def destroy
end
private
def micropost_params
params.require(:micropost).permit(:content)
end
end
I'm thinking that do not have the authorization set up properly for the 'create' action, but I'm not sure exactly how it should be set. I do not have a policy for Pundit for Microposts. I tried adding a simple one but it didn't change anything. I'm learning to put all these pieces together, would someone point me in the right direction?
There is one after action filter verify_authorized because of which you are getting this error. If you have created a policy for the create action then use that to get rid of the error.

Rails 4: strong_params,nested_attributes_for and belongs_to association trouble

I really can't get my head around Rails 4 strong parameters, belongs_to association and form with fields_for.
Imagine I have model for quoting some price:
class Quote < ActiveRecord::Base
belongs_to :fee
accepts_nested_attributes_for :fee
Now, I have seeded some fees into the db, and have put some radiobuttons on my form_for #quote using fields_for. The values of the radiobuttons are simply ids of the records.
Here is the troubling part, the controller:
def create
#quote = Quote.new(quote_params)
...
end
def quote_params
params.require(:quote).permit(:amount_from, fee_attributes: [:id])
end
From my understanding, automagically Rails should fetch fee record with some id, but there is some mystic error instead.
params hash is: "quote"=>{"amount_from"=>"1200", "fee_attributes"=>{"id"=>"1"}}
Log tail:
Completed 404 Not Found in 264ms
ActiveRecord::RecordNotFound (Couldn't find Fee with ID=1 for Quote with ID=)
app/controllers/quotes_controller.rb:14:in `create'
I really don't understand what is going on here, have read Rails association guide, googled for hour for all info, but to no avail.
What I want to achieve here is to understand the correct "Rails way" to fetch some associations for new Quote object using some params I've put in the form.
Guess I got nested_attributes_for wrong, somehow thought it would call Fee.find automagically.
I've opted for ditching fields_for helpers from the form and rendering fields manually like
radio_button_tag 'fee[id]', fee.id
Then in controller I have 2 params methods now:
def quote_params
params.require(:quote).permit(:amount_from)
end
def fee_params
params.require(:fee).permit(:id)
end
And my action looks like
def create
#quote = Quote.new(quote_params)
#quote.fee = Fee.find(fee_params[:id])
...
Any additions on best practices when one has to handle lots of different objects with not so straight init logic are welcome.

Globalize: How to show in the view the current locale information

I am currently having a bit of a problem with Globalize gem.
I explain the current situation:
I have a Model called Question. After creating it, without any data stored, I added the following lines to the model:
class Question < ActiveRecord::Base
translates :wording, :answer1, :answer2, :answer3, :answer4
end
Then, I created a migration to create the translations table
class CreateTranslationsTable < ActiveRecord::Migration
def up
Question.create_translation_table! :wording => :string, :answer1 => :string, :answer2 => :string, :answer3 => :string, :answer4 => :string
def end
def down
Question.drop_translation_table!
def end
My default locale is :en. After that I added some data.
If I go execute rails c and put the command Question.first.wording everything works fine.
Although when I execute in 'rails c' I18n.locale = :es and then I do Question.first.wording still displays the english text I put at the beginning.
I tried one thing which it seemed to help me is that I dropped all the translated columns (like specified in Globalize documentation after you migrated data. In my case I didn't have any data to migrate at the beginning though). After that I made a rollback (which got back the columns I deleted form the Question model), then executing Question.first.wording with I18n.locale = :es got it working. Which means that Question.first.wording returns nil.
After that, I implemented the 'Locale from Url Params' as specified in the Ruby on Rails guide
Which means the first URL param si the ':locale' param.
Now the current problem: The view still displays the information in English when it should display it in Spanish, since the URL I entered was http://localhost.com/es/questions/.
How can I make it to display in the view the Spanish information?
My mistake. I interpreted from the documentation that the the chunck of code (in application_controller.rb) that works for setting the url:
def default_url_options(options={})
{ locale: params[:locale] }
end
would actually set the 'I18n.locale' variable. What I did is the next to get around this (in application_controller.rb):
before_action :change_to_current_locale
def change_to_current_locale
I18n.locale = params[:locale]
end
That made it work.

Cannot get Bubblewrap data from model to controller

I am building an iOS app using the latest version of Rubymotion.
I got a tableview that I would like to fill with data from a remote API.
I named the controller: ProjectsController
I named the model: Project
In the controller viewDidLoad I want to get a list of projects from the API.
I have created a static method in the Project model called load_projects.
def self.load_projects
BW::HTTP.get("#{URL}projects?id=25&project_id=24&access_token=#{TOKEN}") do |response|
result_data = BW::JSON.parse(response.body)
output = result_data["projects"]
output
end
end
This is my viewDidLoad in the controller:
def viewDidLoad
super
#projects = Project.load_projects
self.navigationItem.title = "Projekt"
end
I do not get the same response in the viewDidLoad as I do in the model. In the model method I get the correct response data but in the viewDidLoad I get a "meta" object returned. A BubbleWrap::HTTP::Query object. What am I doing wrong?
Update one
I tried to use the first answer below like this but I get an error:
def tableView(tableView, cellForRowAtIndexPath:indexPath)
cellIdentifier = self.class.name
cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) || begin
cell = UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier:cellIdentifier)
cell
end
project = #projects[indexPath.row]['project']['title']
cell.textLabel.text = project
cell
end
The error is:
projects_controller.rb:32:in `tableView:cellForRowAtIndexPath:': undefined method `[]' for nil:NilClass (NoMethodError)
2012-11-09 01:08:16.913 companyapp[44165:f803] *** Terminating app due to uncaught exception 'NoMethodError', reason: 'projects_controller.rb:32:in `tableView:cellForRowAtIndexPath:': undefined method `[]' for nil:NilClass (NoMethodError)
I can show the returned data here without errors:
def load_data(data)
#projects ||= data
p #projects[0]['project']['title']
end
Ha, I just went through the exact same problem.
The solution I got was the following:
The BW::HTTP method is asynchronous, so your self.load_projects method will return a request object, instead of the JSON data that you want.
Essentially the BW:HTTP.get completes execution immediately and the self.load_projects method returns the incorrect data.
The solution that was suggested to me is the following:
Change your load_projects method so it accepts a view controller delegate:
def self.load_projects(delegate)
BW::HTTP.get("#{URL}projects?id=25&project_id=24&access_token=#{TOKEN}") do |response|
result_data = BW::JSON.parse(response.body)
delegate.load_data(result_data)
delegate.view.reloadData
end
end
Don't forget to reload your data, if you are importing into a table view controller.
Notice that the delegate is calling a load_data method, so make sure your view controller implements that:
class ProjectsController < UIViewController
#...
Projects.load_projects(self)
#...
def load_data(data)
#projects ||= data
end
#...
end
Then do whatever you want with #projects