简体   繁体   中英

Catch postgres trigger in rails controller after insert or update operation

I have an app with different models. One of the models is a badge model with a many to many relation with users via achievements.

In my controllers I have some logic to check if a user has gained an achievement and then make the insert in the relation table (Achievement). After some hard coding in the controller I have decided to take the logic to a trigger in postgresql.

I have programed the trigger for teh first badge that is this:

def change
execute <<-TRIGGER
CREATE OR REPLACE FUNCTION firstbadge() RETURNS trigger AS
$$
DECLARE
BEGIN
IF (select count(id) from User where facebookid=NEW.facebookid)==0 and (select count(id) from Achievement where user_id=NEW.id and badge_id=1)==0 then
    insert into Achievement(user_id,badge_id,created_at,updated_at)values(NEW.id,1,now(),now());
END IF;
RETURN NULL;
END;
$$ LANGUAGE plepgsql VOLATILE;
    DROP TRIGGER IF EXISTS add_badge_user ON paper;
    CREATE TRIGGER add_badge_user
    BEFORE INSERT ON User FOR EACH ROW
    EXECUTE PROCEDURE firstbadge();
TRIGGER
end

And the action in my controller that inserts a new User is:

if !params[:FirstName].blank? and !params[:LastName].blank?
      usuario = User.new
      usuario.facebookid=params[:FacebookId]
      usuario.facebooktoken=params[:FacebookToken]
      usuario.firstname=params[:FirstName]
      usuario.lastname=params[:LastName]
      usuario.identifier=params[:FirstName]
      usuario.age=params[:Age]
      usuario.email=params[:Email]
      usuario.level=0
      usuario.save
      json={:Authorize=> true}
      render :json => json, :status => 200
    end

But I have a little problem, I need the last inserted id from Achievement table (the relation table) in my controller to return it in a JSON. And I have many other functions in My controllers that will need to receive the updated or inserted id's.

How can I catch the results of triggers on postgresql and use them in my controller? Do I have to make a query in my controllers to retrieve the last achievements of the users instead of receiving them from the triggers?

Thank you.

Simply put: you are taking some steps way out of rails' philosophy . Rails is an opinionated framework and if you don't do things following the rails way, it is going to hurt.

First of all, it is generally accepted in rails community that logic should not belong in the database, it should belong in your application . There's a lot of heated talk about this, but if you're going to use rails, you have to get used to it, because the framework is designed that way. So instead of a trigger, you should have used a callback in one of your models .

Other than that, your controller code seems heavily bloated . It is encouraged to keep controller code extremely thin because it is much more maintainable and coherent with MVC architecture (the controller's responsibility should only be to instantiate model objects, perform an action on them, then instantiate a view). A common practice is to push such logic down to the models.

Moreover, it seems that you don't care the least about naming conventions . If you don't follow the rails guidelines about this, you lose a lot of magic and wonder, and make your own life a lot harder. For example, if you had followed the conventions, you could write the controller code you posted this way :

  usario = User.new( params[:user] )
  usario.save
  render json: usario, status: 200

That's 3 lines instead of 14.

Finally, all of this denotes a lack of knowledge about the framework. I strongly encourage you to thoroughly (re-)read the rails guides , and possibly one or two of the many good books there are out there. This will give you a more precise idea of the workflow and design using this wonderful of a tool that is rails.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM