Ruby on Rails DB entry in a model (RoR 3) - ruby

Skip to EDIT2 which works
There is:
Project (has_many :group_permissions)
GroupPermission (belongs_to :project)
I have a form where you can create a new project. A project has several attributes like name, status etc. and now important: iit. iit is selectable with radio buttons: yes or no.
What I want:
If someone selects yes on iit in the Project form, there should be a new record in GroupPermission. So in EVERY project where iit= 1 there should be a certain GroupPermisson.
Can I make / check this in the GroupPermission model? Like if
class GroupPermission < ActiveRecord::Base
if Project.where(iit: 1)
make me a record for each project
end
Can I even make database entries in the model like so?
Is this the right way?
EDIT1:
In the Project controller I added:
if params[:iit] = 1
record = GroupPermission.new(cn: 'ccc-ml', project_id: params[:id])
record.save
end
It then adds a new record in GroupPermissions. But I need the :id of the project. How can I access the id of the project which is about to be saved?
EDIT2
In the Project Controller
after_filter :iit_test, :only => [:create]
...
private
def iit_test
if #trial.iit == 1
record = GroupPermission.new(cn: 'ccc-ml', project_id: #project.id, name: 'CATEGORY_3')
record.save
end
end
EDIT2 works fine. I just have to check it with update etc.
Thank you in advance.

the EDIT2 will only work for apis hitting the controller and not when you add a project via rails console, use in tests etc.
Also this :iit_test will not correctly work for update action as you are creating a new GroupPermission everytime. (GroupPermission may already exists for this project)
You should probably add a callback after_save in the project model and handle adding of a new GroupPermission there.

Write a before action in Project controller like below
def find_project
#project = Project.find_by(id: params[:id])
end
by calling above method in before action you will get the instance of the Project.
Hence you can create the Group Permission by
def create_group_permission
#project.group_permissions.create(cn: 'ccc-ml')
end
The above will create a GroupPermission record with a project id which was found in before action.

Instead of having a method in your projects_controller, you can move the logic to a seperate service. That will make your code easy to test etc..
Something like..
class ProjectsController < ApplicationController
def create
#project = ProjectService.create(project_params)
# rest of your controller code
end
end
#app/services
class ProjectService
def self.create(project_params)
project = Project.new(project_params)
if project.save && project.iit == 1
GroupPermission.create(cn: 'ccc-ml', project_id: project.id, name: 'CATEGORY_3')
end
project
end
end

Related

Class methods vs Instances when using Page object model in ruby

I hope you are having a great day!
I'm wandering something, when using the POM (Page object model) we always create new instances of our classes, like the following simple example:
class LoginPage
def initialize(driver)
#driver = driver
end
def click_button
#driver.find_element(xpath: "//button[#title='Login']").click
end
end
# We create a new instance and we click the button
login_page = LoginPage.new(driver)
login_page.click_button
This makes sense for me, we can create multiple pages if we need to, we can update the state of whatever we need.
However, if we only would have one page open at the time, and we know nothing changes, doesn't it make more sense to take a class method based approach like?:
class LoginPage
class << self
def click_button
#driver.find_element(xpath: "//button[#title='Login']").click
end
end
end
# We create a new instance and we click the button
LoginPage.click_button
Please let me know your ideas, and if you have tried this approach before

Have a token/unique url in order to destroy resource

I would like to add following functionality to one of my models:
Once it's created, a token of some sort will be created and this token allows one to destroy the object e.g. http://localhost:3000/items/7AEaC6Nhq946.
Is there a gem or similiar that offers this functionality already?
You could make a 'Tokenable' concern and include it in the models you want to:
In app/models/concerns/tokenable.rb
module Tokenable
extend ActiveSupport::Concern
included do
before_create :generate_token
end
protected
def generate_token
self.random_token = loop do
random_token = SecureRandom.urlsafe_base64(nil, false)
break random_token unless self.class.exists?(random_token: random_token)
end
end
end
In your model:
include Tokenable
Be sure to add the random_token column in the database for the model where you include the concern.
Now in your controller you would do something like Item.find_by(random_token: params[:random_token]) and perform the actions you wish to do with the object.

Ruby on Rails: Getting a route with Devise

TL;DR How can I achieve this to always return routes with Devise User model ID in custom controllers (i.e. redirecting to localhost:3000/profiles/504026426) with Mongoid?
I have a project that has a social profile controller that returns of a user id with Devise but it will always complain that Mongoid needs a valid ID number in order to work with this route: localhost:3000/profiles/.
# Let's say I want to return a route with id (Devise) without having
# Rails to complain that Mongoid needs to a id of some number.
# So, I have controller containing profiles in the files.
# It goes like..
class ProfilesController < ApplicationController
before_filter :authenticate_user!
# GET /profile/
def index
#user = User.find(params[:id])
end
# .. Snipped for brevity.
end
Is this the right way to do it?
Firstly, the 'params[:id]' you're trying to find the user by won't work in the index view, because you're not passing in any parameter via the url ('profiles/:id' or: localhost:3000/profiles/504026426). If you want to store a user to be available in the index view, use sessions and the current user helper method. See here.
If you want your GET method to work with the 'params[:id]' it would look like:
get 'profile/:id' => 'profiles#show'
make sure it matches a show function in your controller
def show
# this would work with: localhost:3000/profiles/504026426
#user = User.find(params[:id])
end

Troublesome Wice::WiceGridArgumentError

I am working on a Rails 3.1.1 app that is using WICE_GRID and I am stuck on this error.
I want to show a grid of Roles on the User show page. I am setting up the data in the controller like this.
User and Role are related by has_many through user_role.
def show
#user = User.find(params[:id])
#roles = initialize_grid(#user.roles)
end
When I run the site I get this error
Wice::WiceGridArgumentError in UsersController#show
WiceGrid: ActiveRecord model class (second argument) must be a Class derived from ActiveRecord::Base
The error is pointing to #roles = init.... line. initialize_grid does take a record arguent but that is a hash of options, not an activerecord model collection.
When I run the code in the console I see that #user.roles is
[#<Role id: 1, title: "Role1>, #<Role id: 2, title: "Role2">]
Looks like an ActiveRecord collection to me.
Any help gratefully accepted!
initialize_grid takes a class. You're passing in an array of objects. It appears you want to display a user's roles in the grid. You want something like this:
def show
#user = User.find(params[:id])
#roles = initialize_grid(Role, :conditions => ['user_id = ?', #user.id])
end
However, I'm guessing your roles table doesn't have user_id in it. You likely have a mapping table called user_roles. In which case, you will want to refactor the code above. Try just running this code instead to make sure you can view Roles in a grid (unscoped).
def show
#user = User.find(params[:id])
#roles = initialize_grid(Role)
end

Rails Active Record: Calling Build Method Should Not Save To Database Before Calling Save Method

I have a simple user model
class User < ActiveRecord::Base
has_one :user_profile
end
And a simple user_profile model
class UserProfile < ActiveRecord::Base
belongs_to :user
end
The issue is when I call the following build method, without calling the save method, I end up with a new record in the database (if it passes validation)
class UserProfilesController < ApplicationController
def create
#current_user = login_from_session
#user_profile = current_user.build_user_profile(params[:user_profile])
##user_profile.save (even with this line commented out, it still save a new db record)
redirect_to new_user_profile_path
end
Anyyyyyy one have anyyy idea what's going on.
The definition of this method says the following but it's still saving for me
build_association(attributes = {})
Returns a new object of the associated type that has been instantiated with attributes and linked to this object through a foreign key, but has not yet been saved.
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_one
Ok, I'm sure experienced vets already know this, but as a rookie I had to figure it out the long way...let me see if I can explain this without screwing it up
Although I was not directly saving the user_profile object, I noticed in my logs that something was updating the user model's last_activity_time (and the user_profile model) each time I submitted the form (the user model's last_activity date was also updated when the logged in user did various other things too - I later realized this was set in the Sorcery gem configuration).
Per http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html
AutosaveAssociation is a module that takes care of automatically saving associated records when their parent is saved. In my case, the user mode is the parent and the scenario they provide below mirrors my experience.
class Post
has_one :author, :autosave => true
end
post = Post.find(1)
post.title # => "The current global position of migrating ducks"
post.author.name # => "alloy"
post.title = "On the migration of ducks"
post.author.name = "Eloy Duran"
post.save
post.reload
post.title # => "On the migration of ducks"
post.author.name # => "Eloy Duran"
The following resolutions resolved my problem
1. Stopping Sorcery (config setting) from updating the users last_activity_time (for every action)
or
2. Passing an ':autosave => false' option when I set the association in the user model as follows
class User < ActiveRecord::Base
has_one :user_profile, :autosave => false
end

Resources